Hacker News new | ask | show | jobs
by robocat 806 days ago
I thought it was the DOM API that was glacially slow?

Would WASM directly accessing the DOM be an improvement of more than say 5%

1 comments

The DOM has two different APIs, a batch and a piecewise ones. The batch one is incredibly optimized in all the browsers, while the piecewise one usually do not receive any attention at all.

Now, FFI the interface between WASM and JS is incredibly slow. That's by design. I guess the goal was to push every important API into WASM, and leave the FFI just for interfacing code, like on normal environments. People avoid problems with it by batching their data and interfacing as few times as possible, but just like on the JS DOM interface, this is a severe constrain on your code.

Calling between WASM and JS really hasn't been slow in browsers since around 2018:

https://hacks.mozilla.org/2018/10/calls-between-javascript-a...

It would be extremely surprising if calling overhead into JS to manipulate the DOM is noticeable in profiling instead of being dominated by the actual DOM manipulation (I have mainly experience with WebGL and WebGPU, where each call also goes through a JS shim, with a sometimes nontrivial amount of work happening in the JS shim, and the actual call overhead from WASM into JS is absolutely negligable compared to the overall cost, which is typically inside the WebGL and WebGPU implementation).

Also: if performance matters, don't use the DOM in the first place!

> The DOM has two different APIs, a batch and a piecewise ones. The batch one is incredibly optimized in all the browsers, while the piecewise one usually do not receive any attention at all.

What are you talking about?

I'm going to go out on a limb and guess that they mean that if you want to modify the DOM with JS, you cannot batch your updates into an atomic transaction; every modification is applied immediately. However, presumably there is something, somewhere, that can collect modifications and apply them concurrently, because this would be such an insanely obvious optimization to miss for non-JS-driven updates to the DOM (such as initial page load).
It isn't two APIs, but there is effectively some batching. The main thing to focus on is triggering layouts. Basically you want to do all of your reads together then all of your writes.

For example imagine we are trying to move one element to the location of another one. This code will be slow because the read of `leader.offsetTop` will need recalculate the layout to see if that write of `follower.style.left` changed the position of `leader`.

    let x = leader.offsetLeft;
    follower.style.left = `${x}px`;
    let y = leader.offsetTop;
    follower.style.top = `${y}px`;
    
However the following code is fast because it can read all of the values that were calculated during the last render (for the user to see) and doesn't trigger an intermediate relayouts.

    let x = leader.offsetLeft;
    let y = leader.offsetTop;
    follower.style.left = `${x}px`;
    follower.style.top = `${y}px`;
But I am not aware of any explicit batching UI.