Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Large line widgets slow down the editor due to forced reflows #5873

Closed
thomasjm opened this issue May 7, 2019 · 7 comments
Closed

Large line widgets slow down the editor due to forced reflows #5873

thomasjm opened this issue May 7, 2019 · 7 comments

Comments

@thomasjm
Copy link
Contributor

thomasjm commented May 7, 2019

Here's a sandbox showing the issue: https://codepen.io/anon/pen/zQGJMM

If I create a line widget with a large number of DOM nodes, then the CodeMirror instance quickly becomes laggy due to forced reflows. This seems to be because of how CodeMirror measures the line height in functions like updateHeightsInViewport, where it calculates display.lineDiv.offsetTop (the line widget is inside the lineDiv).

In the sandbox I cranked it up to 100k nodes inside the LineWidget to make the problem really noticeable (each edit takes almost 1 second on my computer) but the problem is still noticeable for smaller numbers of DOM nodes.

Is there anything I can do about this? My main use-case is to have a max-height on the LineWidget, so intuitively the height should always be fixed at the maximum when there are large numbers of nodes, so it seems like this should be possible to make fast. Any help would be greatly appreciated.

@thomasjm
Copy link
Contributor Author

thomasjm commented May 7, 2019

Note: turning on the "Verbose" log level in Chrome is a good way to see error messages related to this: recent Chrome outputs messages like [Violation] Forced reflow while executing JavaScript took 883ms

@marijnh
Copy link
Member

marijnh commented May 8, 2019

The way selection works in CodeMirror requires at least one extra forced layout on every update (have to know the selection's position in order to draw it), so unless you can somehow prevent the reflows from recomputing the entire layout in the widget (maybe contain helps here? I'm not sure), I don't see a solution here, except for kludges like putting an empty widget in the editor and overlaying an absolutely positioned element over it.

@thomasjm
Copy link
Contributor Author

thomasjm commented May 8, 2019

Thanks for the quick response! That's cool, I didn't know about contain. Playing in the codepen I can't seem to make it help though.

Huh, so that forced layout is unavoidable? I was reading this article about how forced layout can sometimes be avoided in favor of regular layout, if you order reads and writes in the right way. Is the fundamental issue something like you type a character, then you need to immediately know how wide the character is so that you can place the cursor after it before the next frame?

@marijnh
Copy link
Member

marijnh commented May 8, 2019

about how forced layout can sometimes be avoided in favor of regular layout, if you order reads and writes in the right way.

The editor already does a lot of ordering to minimize the amount of reflows, but yes, that one to measure the cursor position isn't avoidable. At least, not in the current architecture—version 6 will treat selection differently and not have this problem.

@marijnh
Copy link
Member

marijnh commented May 8, 2019

(That being said, each edit will produce at least one reflow no matter what, so if your DOM makes reflows take hundreds of milliseconds, you're going to have a problem either way.)

@thomasjm
Copy link
Contributor Author

thomasjm commented May 8, 2019

Got it, thanks -- I guess it's time for virtual DOM tricks. Closing this now...

@thomasjm thomasjm closed this as completed May 8, 2019
@SteveSonoa
Copy link

I recognize that this issue is marked as closed by the author, but I am also experiencing the same issues with the same symptoms (severe slowdown due to the offsetTop calculation). I'm using CodeMirror to display an API result, and 2 identified use cases return around 90,000 lines. With that calculation only taking a millisecond or two per line, at 90,000 lines, it slows the page to an apparent halt.

Screen Shot 2019-07-09 at 1 05 24 PM
Screen Shot 2019-07-09 at 1 05 43 PM

I will certainly begin testing with the CSS contain you mentioned earlier, but will this component be updated to address the issue natively? Thanks for your time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants