-
Notifications
You must be signed in to change notification settings - Fork 46.9k
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
Webworkers #3092
Comments
So I'm currently thinking of taking the following steps:
Not exactly sure yet about:
Feedback wanted :-) |
@cecilemuller The problem of just using the DOM is that you can no longer integrate with synchronous APIs. So you have to build high level wrapper APIs on the main thread. IMO, the best way of building high level APIs on the main thread is to build them as React components that expose asynchronous APIs. Which is why I think that the solution is react->react rendering. @SanderSpies The top section requires invasive changes to the core but we're working on doing them anyway. What we need help with is all the basic stuff.
|
How do you start a worker?
So yeah, for now I don't see this working without a build tool. My preference would go to the first one. How do you determine the root to render into? It should be possible to have a single worker which is used for multiple components, which makes it a bit more challenging. Probably an extra id needs to be given to communicate to the right component. How do we unit test the system? If there are other options here or I'm missing something, I would definitely like to hear it! |
What progress has been made towards this? |
@bluejamesbond None explicitly for web workers, though we've done a lot of refactoring recently with the goal of making it possible to have multiple reconcilers and make things more serializable, which helps with this goal. |
Any new work in this area? |
No, same as my last message. |
Ok. I may be able to work on this later. Are there technical blockers, or is it just a matter of getting the code written? |
I wrote a custom renderer for ReactJS using Web Workers to try and get some performance numbers. Here is the demo page and the repo. I noticed that for small applications, the cost associated with postMessage seems to make the WebWorker approach slower than using React-dom. For applications like DBMonster when the number of nodes is high, this pays off. The performance also depends on the batching the messages when sent between the web worker and the main UI thread and the batch size needs to be chosen carefully. Here is the detailed analysis. |
@axemclion Thanks for the writeup, that's pretty cool! Your writeup mentioned that the bottle neck appears to become the mutations on the UI thread. Presumably this is because you are mutating the values in every row as frequently as possible, but this is obviously not representative of real-world use cases. It is my belief that most rerenders result in very few changes (That is, the majority of a typical application remains unchanged from one frame to the next). Under the assumption that a typical rerender would do a lot of "work" (calculating diffs) but affect a small number of dom nodes, I wonder if batching becomes less significant and the overall performance benefits of running in a worker become more evident. Especially with respect to things like scroll performance while running a rerender in the background. |
@jimfb You are right about the real world use case - most of the time, there would be expensive dom-diffing, but would result in very little change to the browser DOM. The batching would still be an interesting problem since In the experiment, when I set the batch size to 1 (i.e.) just call I think there is scope for some clever batching, where the UI thread handing the DOM mutations tells us how long those mutations take, and based on that the worker determines the batch size. This way, we don't send so many mutations that we take more than 16ms, or too less that we start building a backup. For scroll, I also tried running the DOM mutations in a |
Forgive me if this is an obvious suggestion, but have you tried benchmarking transferrable objects? |
@pfraze That is a good idea, i could try that. Converting DOM mutations into transferrable objects may be hard though. |
@pfraze I tried transferrable objects, and more simply, just use JSON.stringify - the perf is actually pretty good. It continues to stay that way (better than react-dom), even as the number of objects increase. I am currently running the tests on my machines and will post out the results. Thanks for the suggestion :) |
@axemclion good deal. Have you given any thought to using react-workers as a plugin sandbox? |
Update to the experiment - using JSON.stringify does indeed make web workers implementation faster than react running in a UI thread - here are the numbers - http://blog.nparashuram.com/2016/02/using-webworkers-to-make-react-faster.html. I was also able to get events working, and created a simple todo app @ pfraze, did not understand your comment about react-workers as a plugin sandbox. Can you please explain ? |
@axemclion workers run in a different thread and VM than the page, making them better for sandboxing than iframes. The thread-independence 1. scales better, and 2. prevents a DoS attack ( |
My latest thinking on workers: We definitely want to solve concurrency. It is a major issue to let some work get out of the way. Particularly scrolling and other high-priority interaction that requires immediate feedback. One way to solve that is through cooperative scheduling. I.e. making React and everything around React more "yieldy". Another is by adding preemptive scheduling (OS threads / workers) which adds additional guarantees about hitting frame deadlines. One initial step we could take is move everything into a Worker as proposed here. We can reimplement/replace the DOM. There is, however, one major limitation. Text measurement. Browser layout is currently only available from the main thread. Even if we implement our own layout algorithm ( https://github.com/facebook/css-layout ), we wouldn't have access to text measurement. Even if we implemented our own text measurement, we wouldn't have access to the browser font files for internationalization fallback. Unless browsers are willing to give us text measurement in a Worker, our only option is to do layout on the main thread. React Native doesn't have that limitation because it can get text measurements in the Worker thread. That means that as soon as any of your work in the Worker is dependent on layout, you're going to be sending blocking work to be executed on the main thread. You'll have to wait for the round trip and probably stall the animation/scrolling while doing so. However, luckily for us Compositor Workers are moving along as a spec: This would allow us to keep executing on the main thread, but also put code on the Compositor thread. We could build a React for the Compositor to allow us to easily build components for that thread. If we had that, then it is not clear if React in a Web Worker buys us much more than some potential parallelism at the cost of lost scheduling ability, module initialization overhead (shared code executed twice), serialization overhead and added complexity. If Compositors weren't happening, or if we wanted to render an entire page in WebGL, then we would wait for text measurement in Workers before moving into that model. We could potentially use them to some effect as an intermediate step but it is going to be less than ideal. It would also require a lot of work to port our own code and move the community over to that model completely. Seems safer to wait for compositor workers. I suspect that its implementation will go quick once one browser has it and popular websites are utilizing it. Spec might take a while and it might be fatally underpowered in its first version. So we'll see how long it takes. In the meantime, we have React Native. (Relay in a worker on the other hand seems very plausible.) |
Yup, and we're actively exploring this. |
Hi, Not sure to understand the full problem, but what I understand is that message passing between worker and main thread is expensive. @sebmarkbage instead of focusing on using more powerful workers, shouldn't we focus on making message passing between worker and main thread more efficient? Like for example supporting native support for immutable values, and allowing to pass to worker an immutable object by reference without any serialization? |
@sebmarkbage Just a little question about that, would it be completely silly to think that we could be able to use an embedded font that would work on pretty much all language (From what I remember there is a version of arial that has been developed for that purpose), and to embed corresponding font metrics in js ? |
@Slober It's not terrible expensive and there are ways around it. We should also be focusing on that, and I am, through TC39 but that's an orthogonal problem to this issue. (Edit: Also note that starting up modules and code in each worker isn't free neither. Increases start up time if you have a lot of overlap.) @fdecampredon There are 120,000 unicode characters. When you turn them into glyphs a large number of them have ligature combinations which makes that number explode. Each CJK language have their own font/glyph design for the same character. That explodes that set but most of those are fixed size so maybe you could optimize/compress those. An embedded font, even if it only has all glyph sizes, would be quite large. For proper sizing and shaping you need more information than that. Even if you did that, you would still not have the same exact font combination that that particular browser has. I.e. that gets rasterized on the screen. So you would end up win cases of incorrect measurements. |
Ok it was silly :p thanks for the answer. |
@sebmarkbage Could you please clarify how is this related to the Fiber architecture? Thanks! |
This might be helpful: #7942 (comment) |
I’ll just close this as we’re not actively exploring web workers for the above reasons. |
I understand that we're not exploring this for the above reasons, but I did just want to x-link this project here just in case we revisit: https://github.com/ampproject/worker-dom |
Here is a proposal for react: #18652 . |
Just a question. Why React needs text measurement? AFAIK React only calculates virtual DOM difference and apply changes to browser DOM. Where does React need to care about the actul layouting? |
There has been discussion about webworkers before, @petehunt made already an implementation and @sebmarkbage has some ideas on how he wants to accomplish it within the current code base. If I remember correctly, React should not just run in a webworker but both in the "main thread" and a webworker.
So, what are we waiting for? @sebmarkbage would be great if you could give a more detailed outline of your ideas so we can get this moving :-).
The text was updated successfully, but these errors were encountered: