dom-reconciler-bench icon indicating copy to clipboard operation
dom-reconciler-bench copied to clipboard

Add additional benchmark for optimized implementations

Open NullVoxPopuli opened this issue 5 years ago • 6 comments

Imo, this is needed for perspective of what the existing benchmark is testing.

Could just be a tab at the top that navigates to a page that looks like the existing one, but uses all the idiomatic best practices for managing state

NullVoxPopuli avatar Nov 26 '18 13:11 NullVoxPopuli

What we truly need is to more clearly explain what the benchmark is measuring. And it is probably not even that relevant to benchmark KVO frameworks. See documentation from Glimmer:

Broadly speaking, most component libraries have taken one of two approaches:

  1. Fine-grained property observation, like Ember 1.x.
  2. Virtual DOM diffing, like React.

Systems that rely on property observation trade reduced initial render performance for improved updating speed. That's because they must install observers on every property that gets rendered into the DOM, which takes time. But if a property changes, updates to the DOM are very targeted and fast.

However, web users expect pages to render near instantly. Setting up observers adds a lot of overhead, which slows down initial render. Virtual DOM-based libraries like React have become very popular, because they prioritize raw render speed by keeping change-tracking bookkeeping to a minimum.

The tradeoff is that updates require re-evaluating the component tree to figure out how the DOM needs to be mutated. Essentially, that means doing a full render pass on a component and all of its children every time a property changes.

While constructing virtual DOM is fast and applying diff updates can be optimized, it's far from instanteous, particularly as the size of your application grows. As your virtual DOM-based app grows, you will have to do more work to make sure it stays performant..

The best weapon for optimizing a virtual DOM-based library is something like React's shouldComponentUpdate hook, which lets you quickly tell React that a component hasn't changed and thus you can bypass constructing the virtual DOM tree entirely.

We are essentially trying to measure "re-evaluating the component tree to figure out how the DOM needs to be mutated. Essentially, that means doing a full render pass on a component and all of its children every time a property changes."

My assertion is that Imba introduces a third approach, which looks a lot like Virtual DOM diffing, but is doing it in a very different (much faster) way. It allows for the same performance as "1. fine-grained property observation" without any of the complexity or memory usage. You can manage your state however you want, and still get the performance.

somebee avatar Nov 26 '18 15:11 somebee

Yeah I tend to agree with this statement. KVO was designed to sidestep this problem entirely and predates the VDOM by a good 5 years. It classically did this in a way that made initial render slower. This (along with the general state of jQuery frontends) was the window that allowed VDOM libraries make performance claims and gain ground with arguably less performant and overly complicated solutions.

I do think this is a 3rd approach. There are only a handful of libraries that I know are doing this. It has the ability to not force rerunning the whole code base similar to fine grained KVO, and still has the top down re-render found in VDOM. As it turns out simply equality checking against memoized value at DOM assignment level is generally more performant over even 10k records than following the subscriptions to update the few places that updated. KVO when there aren't many changes is generally faster at these partial updates, but as soon as you consider initial render and cleanup, and other scenarios the benefits start decreasing. It is an interested race though since all the approaches can borrow a bit from each other. In the JS Framework Benchmark the 3 top libraries are an example of each approach DomC(DOM Reconciliation), Surplus(Fine Grained KVO), ivi(VDOM).

What that does mean though is this benchmark is basically non-applicable to KVO and is hugely biased against VDOM libraries which intend to avoid this scenario. Which means it isn't a real comparison testing each library on it's merits, but I'm getting that isn't the point here. It's more to just show performance in this one scenario.

ryansolid avatar Nov 26 '18 15:11 ryansolid

Yeah I tend to agree with this statement. KVO was designed to sidestep this problem entirely and predates the VDOM by a good 5 years.

More than 5 years. http://lambda-the-ultimate.org/node/563

localvoid avatar Nov 27 '18 23:11 localvoid

React implementation is doing extensive binding everywhere, those should be moved to constructor outside render and loops...

https://github.com/somebee/dom-reconciler-bench/blob/master/apps/react/app.jsx#L77 https://github.com/somebee/dom-reconciler-bench/blob/master/apps/react/app.jsx#L83-L86 https://github.com/somebee/dom-reconciler-bench/blob/master/apps/react/app.jsx#L224-L228 https://github.com/somebee/dom-reconciler-bench/blob/master/apps/react/app.jsx#L244 https://github.com/somebee/dom-reconciler-bench/blob/master/apps/react/app.jsx#L261

Havunen avatar Dec 03 '18 16:12 Havunen

oh wow, yeah. binding shouldn't happen every render....

NullVoxPopuli avatar Dec 03 '18 16:12 NullVoxPopuli

The react implementation is pretty much copied from todomvc example. I'd be happy to accept a pull request @Havunen :) Simply tried removing all of the functions (breaks interactivity, but bench still works), and it improved perf by around 5%.

somebee avatar Dec 08 '18 15:12 somebee