Remark: Parsing not blocking the main thread

Created on 3 Apr 2019  路  9Comments  路  Source: remarkjs/remark

Subject of the issue

I have a big markdown file to parse in the browser, and it takes 100% of the CPU to parse it, and in the process my animations become frozen.

Is it possible to somehow yield to the event loop every once in a while?

Your environment

  • MacOS 10.13.6
  • remark-parse: ^5.0.0
  • Google Chrome Version 73.0.3683.86

Steps to reproduce

https://codesandbox.io/embed/qvrw2ywwww

I made this project to reproduce the issue, after the timeout you can see that the animation stops in the middle for a moment.

profile

The image is me running the profiler in my app.

Expected behaviour

Yield to the event loop every once in a while.

Actual behaviour

The parsing is done asynchronously blocking the main thread and freezing animations in the page.

plugin remark-parse 馃憖 areexternal 馃檵 typquestion

Most helpful comment

I feel this is something you鈥檒l run into for every big task in JavaScript. Parsing anything (such as markdown, but also for example syntax highlighting) is a heavy task. And it鈥檒l take up 100% of the CPU. And for big documents that鈥檒l be noticeable. It鈥檚 fastest that way, and I don鈥檛 think it鈥檚 a good idea to build something in to throttle (note: if micromark will become streaming, it would be build in though).

Another thing that may be of interest is, in this case, by using React, you are making good use of the syntax tree. However, syntax trees will always have a big memory footprint compared to a string.

JavaScript already has a system for dealing with this: workers, as @ChristianMurphy mentioned, and unified is pluggable enough to let you parse in a worker, or transform in a worker, or stringify in a worker. I think that鈥檚 the route to take here!

All 9 comments

Is it possible to somehow yield to the event loop every once in a while?

@fcostarodrigo where during the render cycle are you expecting it to pause?

blocking the main thread

One resolution would be to process off main thread using a web worker.
https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers

There are also some web worker abstractions that may help simplify the process:
https://github.com/GoogleChromeLabs/clooney
https://github.com/developit/stockroom

I could be wrong, but it looks like the library ReactMarkdown is exporting a single stateless component and the parsing is being done there. So I guess it is on the render phase in React. In the app, this happens when the user pushes a button, while the button is going away the markdown is being parsed and the button freezes mid animation sometimes.

@fcostarodrigo right, where in remark-parse's cycle would yield?

@ChristianMurphy looking at the profiler, I am guessing between calls to tokenise.

@remarkjs/core Thoughts? :thought_balloon:

I feel this is something you鈥檒l run into for every big task in JavaScript. Parsing anything (such as markdown, but also for example syntax highlighting) is a heavy task. And it鈥檒l take up 100% of the CPU. And for big documents that鈥檒l be noticeable. It鈥檚 fastest that way, and I don鈥檛 think it鈥檚 a good idea to build something in to throttle (note: if micromark will become streaming, it would be build in though).

Another thing that may be of interest is, in this case, by using React, you are making good use of the syntax tree. However, syntax trees will always have a big memory footprint compared to a string.

JavaScript already has a system for dealing with this: workers, as @ChristianMurphy mentioned, and unified is pluggable enough to let you parse in a worker, or transform in a worker, or stringify in a worker. I think that鈥檚 the route to take here!

I tried on my side to lazily use react-dom/server in a webworker to make a wrapper for ReactMarkdown but failed miserably since I couldn鈥檛 just make it work from inside a create-react-app 馃槩it looks like it needs to be built outside to be able to use it.

@fazouane-marouane the ongoing discussion in https://github.com/facebook/create-react-app/issues/3660 may offer some pointers and ideas.

Web workers would be added at a higher level of abstraction than remark-parse, https://github.com/rexxars/react-markdown/issues/289 is a good place to discuss the possibility of adding web workers to the react-markdown integration layer.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

gengjiawen picture gengjiawen  路  4Comments

ikatyang picture ikatyang  路  7Comments

kentcdodds picture kentcdodds  路  4Comments

Jolg42 picture Jolg42  路  4Comments

KyleAMathews picture KyleAMathews  路  6Comments