WordPress.org

Make WordPress Core

Opened 5 years ago

Closed 5 years ago

Last modified 4 years ago

#32197 closed defect (bug) (fixed)

Twemoji script and editor expansion combo making editor ridiculously slow in some circumstances

Reported by: Otto42 Owned by: azaozz
Milestone: 4.2.2 Priority: normal
Severity: major Version: 4.1
Component: TinyMCE Keywords: fixed-major has-patch
Focuses: Cc:
PR Number:

Description

Original report on the forum:
https://wordpress.org/support/topic/text-editor-extremely-slow

I was finally able to reproduce this one. The issue occurs when you have these circumstances:

  1. A really long post. I found that about 60000 characters of Lorem Ipsum showcases it quite well.
  1. Use the Text editor. The Visual editor largely seems unaffected. Not sure why.
  1. The "Enable full-height editor and distraction-free functionality." must be enabled.

When these conditions are met, every interaction with the textarea, clicks, typing characters, just about anything, gets picked up by the MutationObserver in wp-emoji.js, passed through parse(), and eventually into parseNode() in the twemoji.js.

Since the node in question is the textarea, it runs that big ugly 10000 byte regular expression across the entirety of the post content... on every keypress or other interaction with the textarea.

Different browsers handle this differently.

Chrome on Windows 8 doesn't seem to care much (fast JS indeed) until there is a 2-byte character anywhere in the post. The easiest way to trigger the lag is by inserting a copy/pasted "smart quote" into the post. U+201C works. This makes the re.exec() in twemoji.js go from a 80ms run to 1.5s or so.

Firefox on Windows 8 shows a noticable amount of lag regardless. The amount seems to correlate with the size of the post content.

Note that either disabling wp-emoji.js or turning off the editor-expand in the Screen Options will "fix" the problem for the short term.

Attachments (5)

32197.patch (2.4 KB) - added by iseulde 5 years ago.
32197.2.patch (2.3 KB) - added by iseulde 5 years ago.
32197.3.patch (4.0 KB) - added by azaozz 5 years ago.
32197.4.patch (4.3 KB) - added by iseulde 5 years ago.
32197.5.patch (4.2 KB) - added by iseulde 3 years ago.

Download all attachments as: .zip

Change History (33)

#1 @ocean90
5 years ago

Duplicate of #32196?

#2 @Otto42
5 years ago

#32196 was marked as a duplicate.

#3 @ocean90
5 years ago

Related: #32156.

#4 @Otto42
5 years ago

Definitely related: #32125 . I was seeing the same multiple second execution time in parseNode as well.

#5 @Otto42
5 years ago

The patch in #32125 does not solve this problem, it merely moves it to the "test" function instead of the "parseNode" function.

#6 follow-up: @azaozz
5 years ago

  • Milestone changed from Awaiting Review to 4.3
  • Version changed from 4.2 to 4.1

This is a problem with the textarea resize function. On keyup it copies all content from the textarea to a hidden div, then calculates the div height and sets the textarea height. For a long post that can become very slow.

Now this is amplified by the emoji replacement. Adding the content to the hidden div triggers re-parsing of the whole content.

Last edited 5 years ago by azaozz (previous) (diff)

#7 @Otto42
5 years ago

Ahh. And because the MutationObserver is watching document.body, it sees the change to the hidden div, and triggers.

Perhaps that MutationObserver should ignore anything that with a class that contains "clone" and not try to parse it.

#8 in reply to: ↑ 6 @rowd1951
5 years ago

Replying to azaozz:

This is a problem with the textarea resize function. On keyup it copies all content from the textarea to a hidden div, then calculates the div height and sets the textarea height. For a long post that can become very slow.

Now this is amplified by the emoji replacement. Adding the content to the hidden div triggers re-parsing of the whole content.

Hi @azaozz, I submitted my own ticket relating to the manifestation of this problem as it appeared for me, here: #32196

For me, the post in text mode could be extremely long - say, 16,000 words (not characters) of lipsum, and I wouldn't experience any delay.

I only experience a delay when I put in, say, a single bullet point or a curly quote among those 16,000 words.

As soon as that character is deleted, text editor works like a charm again, with no lag whatsoever.

However, your comment seems to suggest that this bug would lead to a lag when typing any text into a long post, but for me this isn't the case, it's only when a non-standard character is present among a lot of text.

Could you explain what it is about, say, a bullet point or a curly quote, for instance, that has such a terminal effect on lag? When normal characters don't?

Last edited 5 years ago by SergeyBiryukov (previous) (diff)

#9 @Otto42
5 years ago

@rowd1951 that particular part looks like a Chrome bug to me. Still looking into why that has such a devastating effect on the regular expression. Firefox doesn't show the same issue with those characters.

#10 @azaozz
5 years ago

@Otto42 right, a straightforward fix would be to add an "exclude" class to that div and then check for it when before calling test() or parse() from the mutation observer. A better fix would be if we can find a better way to resize the textarea :)

@rowd1951 also suspecting this depends on the Twemoji's test regex. It is very long: https://github.com/twitter/twemoji/blob/gh-pages/twemoji.js#L236

#11 @SergeyBiryukov
5 years ago

  • Milestone changed from 4.3 to 4.2.2

Moving for 4.2.2 consideration.

#12 @Otto42
5 years ago

Definitely a Chrome thing, somehow.

Test in Chrome console. "re" is already defined as that big twemoji regexp.

console.time('a'); for (i = 1; i <= 10000; i++) re.test('1111111111111111111'); console.timeEnd('a');
a: 14.108ms

console.time('a'); for (i = 1; i <= 10000; i++) re.test('111111111111111111“'); console.timeEnd('a');
a: 2762.734ms

Not sure why, but it really hates those special characters.

#13 @Otto42
5 years ago

Firefox 37.0.2 cares too, but not quite as much:

console.time('a'); for (i = 1; i <= 10000; i++) re.test('1111111111111111111'); console.timeEnd('a');
a: 9.82ms

console.time('a'); for (i = 1; i <= 10000; i++) re.test('111111111111111111“'); console.timeEnd('a');
a: 85.79ms

#14 @MarioKnight
5 years ago

Definitely related to #32156 that I put in earlier this week. Disabling the full-height editor did take away this lag. I can also confirm on my end that it is only in place when special characters are in use. The page on my site that brought the issue to my attention contains Japanese text. I found a page on my site that fits the size requirements without any Japanese text, and I could use the text editor with no issues. Copying a “ character as mentioned in the forum thread immediately cause the issue to come up. Taking it away would take away the issue as well.

Now I have to wonder why I was under the impression I didn't notice the issue prior to the 4.2.1 update as I quoted in my ticket. I'm going to guess it was a combination of doing mostly a couple of copy and pastes, and potentially a lack of coffee. In any case, since my issues match exactly what's mentioned above, I think it should be safe to close my ticket as a duplicate and continue this one.

#15 @Otto42
5 years ago

#32156 was marked as a duplicate.

@iseulde
5 years ago

#16 @iseulde
5 years ago

Above patch has more efficient resizing, without a clone. Now we need a way to detect the cursor position to keep the cursor in view, but that's less vital. Ideally we need to move to something like this anyway. Cloning the content is slow and error prone. It's a start. Not sure if this would be good for 4.2.2, we might just want to ignore the clone for now.

This ticket was mentioned in Slack in #core-editor by azaozz. View the logs.


5 years ago

@iseulde
5 years ago

@azaozz
5 years ago

#18 @azaozz
5 years ago

Still feels somewhat slow for long posts. Caused by the (unnoticeable) scrolling on every keyup (input), as we reduce the textarea height to about 100px then immediately set it to ~3000px.

32197.3.patch: look at the textEditor.value.length before attempting to reduce the height. That makes it quite faster for very long posts.

Last edited 5 years ago by azaozz (previous) (diff)

@iseulde
5 years ago

#19 @iseulde
5 years ago

So these patches remove some functionality. If your cursor moves under the top or bottom toolbar, it will no longer scroll the cursor into view. I've tried doing it without cloning the content to detect the cursor position, but this seems to be the only way. We might have to ignore the cloned div for now...

#20 @Otto42
5 years ago

I put in a bug report with chrome:
https://code.google.com/p/chromium/issues/detail?id=482998

With an associated jsfiddle that demonstrates that problem:
https://jsfiddle.net/7vo8wteu/

Note that the fiddle works in Firefox too, with vastly different results.

This doesn't change the problem here though. We still probably should ignore that clone div.

#21 @iseulde
5 years ago

Even without the curly quote this seems to be very slow in Safari.

#22 @azaozz
5 years ago

In 32336:

Emoji: add an exclude class to wp-emoji checked when monitoring for changes with mutationObserver. Use it for the hidden div used for resizing the Text editor.
See #32197.

#23 @azaozz
5 years ago

  • Keywords fixed-major has-patch added

Right, checking a class before processing works well. Leaving open in case we want a different name for the exclude class.

#24 @azaozz
5 years ago

In 32337:

Emoji: rename the exclude class to wp-exclude-emoji.
Props Clorith. See #32197.

#25 @azaozz
5 years ago

  • Owner set to azaozz
  • Resolution set to fixed
  • Status changed from new to closed

In 32362:

Emoji: add an exclude class to wp-emoji checked when monitoring for changes with MutationObserver. Use it for the hidden div used for resizing the Text editor.
Fixes #32197 for 4.2.

#26 @Otto42
4 years ago

FYI: Chromium has now made a change to fix this issue, which will likely hit stable in a couple months:

https://code.google.com/p/chromium/issues/detail?id=482998

#27 @programmin
4 years ago

In a recent profiler run I was also noticing consecutive slow calls to twemoji test, twemoji.js:561 took about 660ms repeatedly (initializing multiple editors).

I was testing on Chrome 44, and WP 4.3 RC. Is this the same issue?

#28 @Otto42
4 years ago

@programmin : I'm not sure about Chrome 44, however, Chrome 45, currently in the beta channel, has a working fix for this.

If you run the jsfiddle I posted before: https://jsfiddle.net/7vo8wteu/

In Chrome 45.0.2454.78 beta-m (64-bit), the results are 2ms and 4ms, respectively, instead of the ludicrous 2k+ ms results that it had before. The numbers vary a bit, but they're always under 10ms now for me.

So, looks like Chrome will ultimately solve the issue here as well.

@iseulde
3 years ago

Note: See TracTickets for help on using tickets.