It would be unimaginably difficult to convince Apple, Google, Microsoft and Mozilla to standardize a low-level DOM API.
When writing most non-web software, you can usually write it quickly in a high-level language (with a rich standard library and garbage collection), but you can get better performance (with more developer effort) by writing your code in a lower-level language like C or Rust.
WebAssembly runs code in low-level languages on the web. That seems like an opportunity to get better performance by rewriting JavaScript web apps in Rust, but it doesn’t (usually) work that way.
When you write a JavaScript web app today, the primary thing you’re interacting with is the Document Object Model (DOM). You’re adding/removing/updating elements and their attributes on the page, and responding to events (like click events, keyboard events, etc.) These are all features of the DOM API.
WebAssembly doesn’t have direct access to any of that. WebAssembly has some limited (and fairly slow) facilities to call JavaScript, and to interact with the DOM that way, but WebAssembly can’t modify the DOM or respond to events directly.
And it’s not going to happen any time soon, because of standardization.
The web’s core DOM APIs are defined in standards committees as inherently JavaScript APIs, in the form of WebIDL documents.
When defining standardized APIs in WebIDL, WebIDL assumes that you can use JavaScript strings, JavaScript objects + properties, JavaScript Exceptions, JavaScript Promises, JavaScript garbage collection, and on and on and on. Almost all of the specification of WebIDL itself is about the dozens of types that it assumes the platform already provides. https://webidl.spec.whatwg.org/
WebAssembly doesn’t have any of those things. As a low-level VM, it supports only modules, functions, bytes, numbers (32-bit and 64-bit integers and floats), arrays (called “tables”), and opaque pointers (“reference types”).
In WebAssembly, if you want to read a JavaScript string (or any JS object), you have to serialize it (in JavaScript) into an array of bytes, and transfer that array into WebAssembly memory. If you want to send a string to JavaScript, you then have to deserialize the byte array back into a JavaScript string object.
All of this is usually slower than just working with the string in JavaScript directly.
(Historically you had to transfer data into WebAssembly by copying byte arrays, which was quite slow, but you can now share the byte arrays by reference. There is also a new-ish facility for WebAssembly called “interface types” that make it simpler to serialize/deserialize the data. You wouldn’t have to provide your own JS code to do it; the platform could serialize and deserialize strings/objects automatically. But you’re still running an O(n) algorithm on every piece of data you read/write, inherently doing more work than JS needs to do, no matter how optimized the serialization gets.)
No one has ever standardized a DOM API for low-level languages. You’d presumably a need to start by defining new low-level WebIDL design language just to define a low-level DOM API!
And that’s why you can’t get top-notch performance by rewriting your web app in Rust. You can rewrite your web app in Rust, and it can access JS APIs, but when touching the DOM APIs, your Rust has to interop with JS.
Rust’s interop with JS is no faster than JS itself. In fact, it’s usually slower, because it requires serializing/deserializing between JavaScript strings/objects and WebAssembly byte arrays.
As a result, if you’re writing a web app, you mostly have to do it in JS. If you have some very CPU-intensive code that just does a little bit of I/O at the beginning/end, you can write that in WASM and send the result of your computation to JS, as long as you don’t cross the boundary between WebAssembly and JS too often.
Alternately, if you have existing code in non-JS languages, you can port it to web via WASM, but it’ll probably run slower that way. The best performance improvement you can do is to rewrite it in JS!
Designing the web by committee makes it hard to add/change stuff in browsers. You have to get Apple, Google, Microsoft, and Mozilla to agree on literally everything. (Defining WebIDL itself has taken decades!)
It can be hard to even get agreement from browser vendors to discuss the same topic, to even just get them to read your proposed standards document and to say “no, we won’t implement it like this, because…” You have to convince them that the standard you’re proposing is one of their top priorities. (And before you can do that, you have to convince them to pay attention to you at all.)
So, someone would have to persuade all of the browser vendors that one of their top priorities should be to invent a new way to standardize DOM APIs and begin the process of standardizing DOM on top of a lower-level IDL.
Daniel Ehrenberg recently published an article on this, titled, “When Is WebAssembly Going to Get DOM Support? Or, how I learned to stop worrying and love glue code”
The key line is:
For now, web folks don’t seem to be sold on the urgency of this very large project. There is no active work by browser vendors in this direction.
Today, the browser vendors aren’t convinced that this is worth their time. It’s better to make existing JS web apps faster than it is to begin a multi-year (multi-decade?) project to make a new thing possible that could be better in the long run.
In fact, most folks in the WebAssembly standards committee (WASM CG) aren’t convinced it’s worth it, either.
For each of these features, as well as direct DOM/web API access, browser vendors will decide whether to implement the feature based on whether it improves actual performance or code size.
Why aren’t they all fired up about this?
I think it’s because they see that the path to standardizing a truly low-level DOM API is basically impossible in the next decade.
So, don’t hold your breath!
.png)

