44
loading...
This website collects cookies to deliver better user experience
Plug: I work on Million.js: <1kb virtual DOM - it's fast!
list-diff2
), the time complexity is O(n)
in the best case (not including the O(n^3
time complexity baseline for diffing). Repeat this for all the children in a vnode tree and you can just imagine how inefficient this can be. O(1)
operations, but also gracefully falls back to normal diffing when necessary. Additionally, bundle sizes decrease significantly, reducing the amount of code that needs to be executed at runtime.Keys: Specify the identity of a vnode
Keys are useful when you know that a certain vnode's position, data, and children will not change between two states. Keys can be provided by the user manually, or generated by the compiler. This allows for the vnode to be skipped entirely, avoiding unnecessary diffing (
O(1)
)
Flags: Specify the type of content of a vnode's children.
Flags allow for diffing to skip certain computationally expensive condition branches. For example, if the vnode's children only contains text nodes, then just setting the
textContent
of the element would be significantly faster than constructing and replacing a text node. Million.js currently only supports 3 flags:NO_CHILDREN
(O(1)
),ONLY_TEXT_CHILDREN
(O(n)
), andANY_CHILDREN
(O(n^3)
).
Deltas: Specify predictive and consistent modifications of a vnode's children.
Deltas can be utilized when simple, imperative micro-actions can be predicted through static analysis. Deltas by default are a series of imperative operations, but leverage the internal diffing algorithm to reduce DOM manipulations. Million.js currently supports 3 fundemental Delta operations:
INSERT
(O(1)
),UPDATE
(O(1) to O(n^3)
),DELETE
(O(1)
).
Leveraging Million.js features:
The primary way to optimize for Million.js is just leverage the compiler-focused features that it provides. This is the only way to reduce diffing assuming that the patch scope remains constant.
Prerendering + reducing dynamic content
Another way of making performance better is to not even consider static content by reducing the patching scope—especially if your application is only interactive in certain areas. This is even more efficient than generating imperative DOM operations, as DOM manipulation won't even be needed! Additionally, the initial vnode should be prerendered the page, so that the page doesn't need to be fully initialized at runtime.
Bad:
<div></div> inject <button>Click Me!</button>
Good:
<div><button>Click Me!</button></div>
Static vnode + props hoisting:
A standard optimization to hoist vnodes and props that are static, allowing them to be cached and incurr no generation computational cost. This is best illustrated with a code sample:
// Without static VNode hoist
const render = () => patch(el, m('div', undefined, [`My favorite number: ${1 + 2 + 3}`]))
render();
render(); // Static VNode needs to be constructed twice
// With static VNode hoist
const _s = <div>Hello World!</div>
const render = () => patch(el, _s)
render();
render(); // Static VNode is used twice and cached
// Without static props hoist
const render = () => patch(el, m('div', { id: `app${1 + 2 + 3}` }))
render();
render(); // Static props need to be constructed twice
// With static props hoist
const _s = { id: `app${1 + 2 + 3}` };
const render = () => patch(el, m('div', _s))
render();
render(); // Static props are used twice and cached