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

Do virtual DOM diffing on web worker? #417

Closed
alastaircoote opened this issue Nov 24, 2016 · 17 comments
Closed

Do virtual DOM diffing on web worker? #417

alastaircoote opened this issue Nov 24, 2016 · 17 comments

Comments

@alastaircoote
Copy link

This is an entirely speculative request, just wanted to get opinions from the devs on how challenging it would be.

Some people have done experiments on splitting the virtual DOM diffing and actual DOM operations up, so that the former run in a web/service worker, boosting performance.

It sounds like it'll take a lot of work to integrate this into React - I'm curious to know the same about Preact. Just based on the code size alone I'm hoping it might be simpler! Happy to help out in any way that I can.

@developit
Copy link
Member

This is an awesome idea and something I've actually been playing with in my spare time. It's really easy to do in preact, too. I don't have performance testing done or anything though, so I can't say whether or not it's super valuable. I'll wrap up my demo stuff and post a link to it here so we can hack on it in the open 🎉

@alastaircoote
Copy link
Author

That's great to hear. I'm actually experimenting with a PWA where the service worker renders Preact components to string in response to fetch events, then the client JS takes over on load. There's a lot of back and forth between the worker and the client (for data retrieval etc) so I'd be really interested to see how much I could cut that down with worker-side logic.

But anyway. Eager to see what you've been working on!

@tusharmath
Copy link
Contributor

@alastaircoote IMHO I haven't found it to be of much practical use. I make sure that the DOM is updated only once per anime frame. Which gives me close to 16.7ms to do all the computations including VDom diffs/updates, layouts etc. With preact in a fairly large application and where I am heavily updating the DOM I am able to finish my work well within 3ms. Now this could be done faster, may be within 1ms if parallized using workers but that would not be of much value since I am well under the specified limit. Its like driving a lamborghini on road which has a speed limit of 40kmph.

I chose preact/snabbdom for this particular reason as with react I was not able to finish of my computation within 16ms in some scenarios. But now the code is not only less bloated and Fast Enough.

@developit
Copy link
Member

Ah - I meant to post here, but I finished up my experiment with running an entire preact app in a web worker. The results are interesting, still looking into what it might be useful for.

Tweets:

https://twitter.com/_developit/status/805228887366107137
https://twitter.com/_developit/status/805197568804343809
https://twitter.com/_developit/status/805295723159896065
https://twitter.com/_developit/status/805291782074404864
https://twitter.com/_developit/status/805535262772199424

@alastaircoote
Copy link
Author

That's awesome. How are you transferring the DOM change operations to the main thread? As @tusharmath mentions, I suppose the important comparison here is DOM diffing time vs. worker communication overhead time, and whether the latter is less than the former.

@developit
Copy link
Member

Currently the demo tracks DOM changes via MutationObserver (undom's implementation) and the MutationRecord objects are passed up to the main thread. They are very small because every element is assigned an __id on creation, and subsequent mutations for an element with an existing id just sends the id.

@developit
Copy link
Member

apparently this thread is on the front page of hacker news. thanks for prodding me to finish up this experiment @alastaircoote 😂

@LMnet
Copy link

LMnet commented Dec 8, 2016

I think this feature request is too wide. There is more than one web worker scenario:

  1. Main thread - app, worker - diff.
  2. Main thread - only dom stuff, worker - app + diff.
  3. Main thread - only dom stuff, worker1 - app, worker2 - diff.

All this scenarios are very different and needs different improvements in the Preact.

@developit
Copy link
Member

@LMnet #2 in your list is what I showed in the demo, #3 I'm not sure is possible, or at least the overhead of pushing VDOM into a worker just to diff it would be pretty extreme (you'd have to pass the whole VDOM tree, which is quite large).

I left this issue open because I have not yet released the source of the demo, but once I do so I think it would make sense to close the issue out - there will be a library that lets you run apps in a Worker given a bunch of constraints, and an example of its use.

That being said, I'd recommend taking anything worker-based with a grain of salt. Just moving the diff itself into a Worker is slower than diffing in the main thread, because of serialization overhead and the fact that it's diffing against the DOM, so you then have to set up a proxy DOM in the worker. In reality, the performance impact of Preact's diff in a real world application is minimal - the DOM operations performed as a result of that diff are the real cost. Moving the diff into a worker doesn't do anything to reduce that cost, it just adds threading complexity and overhead.

This is not to say that Workers are useless (far from it!), simply that they are best used in cases where a task fits the constraints inherent to them: small input + output size, large cost of work. Some examples of things that are well-suited to running in a Worker:

  • transpilation / transformation (example: Preact's REPL)
  • proxying and caching (via ServiceWorker, avoiding data transfer overhead)
  • sandboxing (near and dear to my heart)

@leeoniya
Copy link

leeoniya commented Dec 9, 2016

i also have a lib in the vdom space. here's my take on Workers. they're not worth it.

as an example [1], dbmonster bench at 0% mutations (measuring just lib overhead without dom ops)

a full re-generation of its vdom (a few thousand nodes), full diff and dom reconciliation takes just 1.17ms on a T440S thinkpad (several years old).

a lib would have to be really inefficient to benefit from any kind of worker offloading. it can serve as a stop-gap fix (maybe), but long-term it won't get anywhere near the perf gains of satisfying the JIT and GC.

/ $0.02

[1] https://rawgit.com/leeoniya/domvm/2.x-dev/demos/bench/dbmonster/index.html

@developit
Copy link
Member

@leeoniya good to know! It seems like consensus is basically that it's not the best use-case for a worker 👍

@developit developit mentioned this issue Dec 12, 2016
@developit
Copy link
Member

Think we can close this issue out?

@alastaircoote
Copy link
Author

I think so - my curiosity is satisfied anyway! Given a lot of my app logic lives inside the worker it still might make sense for me to do it, but it'll be a little while before I can fully test it out.

@developit
Copy link
Member

Yup! Now the option is there. Hopefully I'll be able to clean up that demo and publish it shortly :)

@okbel
Copy link

okbel commented Dec 11, 2019

Any news?

@marvinhagemeister
Copy link
Member

@okbel The situation hasn't changed, the serialization cost to move things between the worker and the main thread are still to high and make this not a worthwhile endeavor to pursue for frameworks.

@tusharmath
Copy link
Contributor

tusharmath commented Dec 12, 2019 via email

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

No branches or pull requests

7 participants