Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

That old thing again ;)

Direct DOM access doesn't make any sense as a WASM feature.

It would be at best a web-browser feature which browser vendors need to implement outside of WASM (by defining a standardized C-API which maps to the DOM JS API and exposing that C API directly to WASM via the function import table - but that idea is exactly as horrible in practice as it sounds in theory).

If you need to manipulate the DOM - just do that in JS, calling from WASM into JS is cheap, and JS is surprisingly fast too. Just make sure that the JS code has enough 'meat', e.g. don't call accross the WASM/JS boundary for every single DOM method call or property change. While the call itself is fast, the string conversion from the source language specific string representation on the WASM heap into JS strings and back is not free (getting rid of this string marshalling would be the only theoretical advantage of a 'native' WASM DOM API).



> If you need to manipulate the DOM - just do that in JS, calling from WASM into JS is cheap, and JS is surprisingly fast too.

From the point of view of someone who doesn't do web development at all, and to whom JS seems entirely cryptic: This argument is weird. Why is this specific (seemingly extremely useful!) "web thing" guarded by a specific language? Why would something with the generality and wide scope of WASM relegate that specific useful thing to a particular language? A language that, in the context of what WASM wants to do in making the web "just another platform", is pretty niche (for any non-web-person)?

For me, as a non-web-person, the big allure of WASM is the browser as "just another platform". The one web-specific thing that seems sensible to keep is the DOM. But if manipulating that requires learning web-specific languages, then so be it, I'll just grab a canvas and paint everything myself. I think we give up something if we start going that route.


Think of it as traditional FFI (foreign function interface) situation.

Many important libraries have been written in C and only come with a C API. To use those libraries in non-C languages (such as Java) you need a mechanism to call from Java into C APIs, and most non-C language have that feature (e.g. for Java this was called JNI but has now been replaced by this: https://docs.oracle.com/en/java/javase/21/core/foreign-funct...), e.g. C APIs are a sort of lingua franca of the computing world.

The DOM is the same thing as those C libraries, an important library that's only available with an API for a single language, but this language is Javascript instead of C.

To use such a JS library API from a non-JS language you need an FFI mechanism quite similar to the C FFI that's been implemented in most native programming languages. Being able to call efficiently back and forth between WASM and JS is this FFI feature, but you need some minimal JS glue code for marshalling complex arguments between the WASM and JS side (but you also need to do that in native scenarios, for instance you can't directly pass a Java string into a C API).


Sure, but if someone came at the C-centric ecosystem today and said "let's do the work to make it so that any language can play in this world", then surely "just FFI through C" would be considered rather underwhelming?


Well that's what the WASM Component Model set out to solve, some sort of next-gen FFI standard that goes beyond C APIs:

https://component-model.bytecodealliance.org/

In my opinion it's an overengineered boondoggle, since "C APIs ought to be good enough for anything", but maybe something useful will eventually come out of it, so far it looks like it mostly replaces the idea of C-APIs as lingua-franca with "a random collection of Rust stdlib types" as lingua-france, which at least to me sounds utterly uninteresting.


While it can function as an FFI (it is indeed the basis of WASI) the component model is more about composability and interfaces


Wow, I've used JNI many times, but many years ago. It is a bit painful. Cool to see it's been replaced by FFM, didn't know that existed.


DOM API interactions with JS are already described with a DDL, they're not exactly native JS APIs.


The practical argument is that while initially the DOM API was developed to be language agnostic with more of an eye to Java/C++ than JavaScript since a while ago this is no longer the case and many web APIs use JavaScript data types and interfaces (eg async iterators) that do not map well to wasm

The good news is that you can use very minimal glue code with just a few functions to do most JavaScript operations


WASM is an abbreviation for WebAssembly. If it doesn't have DOM access, WebAssembly is as related to the Web as JavaScript is to Java. A language ecosystem with no I/O capability is as much use as a one-legged man at an arse-kicking party.


Webgl can't access the dom either


That's opengl on the web, a graphic api, you can't compare the two


I agree, but my point is that a language can be useful even if it does not have access to everything


Well, arguably the worst thing about WASM is the naming.

It's neither directly related to the web, nor is it an assembly syntax.

It's just another virtual ISA. "Direct DOM access for WASM" makes about as much sense as "direct C++ stdlib access for the x86 instruction set" - none ;)


If you want to compare the situation to x86, direct DOM access for WebAssembly is more akin to the BIOS than C++ stdlib access. If it can't interact with the outside world, it's just a very special toy that you can only use to play a game that isn't any fun, and a good candidate for those 'What's the next COBOL?' discussions that come up every now and then.


It's basically that joke about Haskell, that nobody uses it because it can't have any effect... but for WASM the developers are insisting on making sure it's real.


Oh wow, that really is terrible naming... I always thought WASM was a specification for compiling code into something that runs natively in web browsers—like a web-specific compilation target.. Today I learned.


It's an instruction set architecture that browsers happen to support executing directly.


In German, often things are named for where they came from, like Berliner or Frankfurter. WebAssembly came from the web, so makes sense :)


WASM is to webbrowsers what WebGPU is to webbrowsers. Designed with browsers in mind, but not bound to them.


Like C, which offloads IO to the standard library?


It's still there - you can still do I/O in C, even if you have to call a library function. In WebAssembly, there's no mechanism for I/O of any sort.


But that's not the (original) argument being made. Just as IO belongs in POSIX and not C, DOM access belongs in some other standard, not WASM


There is, it is just called WASI and it specifies syscalls in a different way.

WebASM is an assembly-like dialect, after all.


...in WASM you also call a function to do IO though? That function is just provided by the host environment via the function import table, but conceptually it's the exact same thing as a Linux syscall, a BIOS int-call or calling into a Windows system DLL.


As long as that function doesn't receive any parameter that is like any data actually on the DOM.

So you either create a very concrete JS library that translates specific WASM data into IO actions, or one that serializes and deserialize everything all around but can be standardized.

At this point, none of those options are much more capable than Java applets... Or, in fact, if you put a network call between the WASM and the JS, you won't even add much complexity.


> At this point, none of those options are much more capable than Java applets

Java applets allowed to load and call into native DLLs via JNI, so they were definitely much more capable than WASM, but also irresponsibly unsafe.

In your own WASM host implementation you could even implement a dlopen() and dlsym() to load and call into native DLLs, but any WASM host which cares about safety wouldn't allow that (especially web browsers).


That's not really much different from writing a language runtime for any other OS. If you're writing the Linux or Windows IO routines for say Haskell or Python or Scheme, you're writing them in C, and then you either call into them from the language's FFI or invoke platform ABI calls into the runtime from the compiled code.


Isn’t the whole reason why people want DOM access is so that the JavaScript side doesn’t have any meat to it and they can write their entire web app in Rust/Go/Swift/etc compiled to webasm without performance concerns?


Spoiler: there will be performance concerns.

The bottleneck is in the DOM operations themselves, not javascript. This is the reason virtual-dom approaches exist: it is faster to operate on an intermediate representation in JS than the DOM itself, where even reading an attribute might be costly.


This isn't true. DOM access is fast. DOM manipulation is also fast. The issue is many DOM manipulations happening all at once constantly that trigger redraws. Redrawing the DOM can also be fast if the particular DOM being redrawn is relatively small. React was created because Facebook's DOM was enormous. And they wanted to constantly redraw the screen on every single interaction. So manipulating multiple elements simultaneously caused their rendering to be slow. So they basically found a way to package them all into a single redraw, making it seem faster.


It’s the interlacing that’s the cost. Read after write forces redraw.

My big win on my first AJAX app was splitting read and write into two phases to reduce a page load from 30s on IE6 down to about 2 seconds. I didn’t even have to rearchitect. It was one loop in one (maybe 2) functions. Just had to split it into 2 loops.

If React wins (which I don’t agree that it does, but don’t want to have that argument), it’s that it allows you to compose tricks like this across a whole page instead of one component type.


All of the issues with reflow, layout invalidation, forced layout on property access, recalculating styles, which require careful solutions like batching change operations and optimized rendering strategies, will also affect anything operating on the DOM via WASM.

The point stands; maybe a faster VDOM can be built in a compile-to-wasm language, though the bottleneck will remain the browser's DOM API and rendering, not the language interpreter.


From my own time in the trenches working on ridiculously complex and dense web UIs:

I’ve always found this a bit specious. And indeed there are any number of libraries out there that are 4x faster than React these days. The problem is not access it’s pipelining. When the DOM is relatively homogenous there are simple code transformations and idioms that increase the render throughput by 10-50x or more. It’s interlacing reads and writes in a sequence that’s murder. So when you get to a heterogenous DOM with many different people working on different parts, it gets awkward to prevent the interlacing.

The virtual DOM is one way to force the separation, but it’s not the only way and it adds a lot of overhead, both computationally and cognitively. I can’t wait for it to die in a fire.


> without performance concerns?

WASM isn't going to magically make the DOM go faster. DOM will still be just as slow as it is with Javascript driving it.

WASM is great for heavy-lifting, like implementing FFMPEG in the browser. DOM is still going to be something people (questionably) complain about even if WASM had direct access to it. And WASM isn't only used in the browser, it's also running back-end workloads too where there is no DOM, so a lot of use cases for WASM are already not using DOM at all.


> Direct DOM access doesn't make any sense as a WASM feature.

I disagree. The idea of doing DOM manipulation in a language that is not Javascript was *the main reason* I was ever excited about WASM.


You can't even run wasm in browsers without JavaScript, it is not a supported <script /> type

Anyway I am quite sure that you could almost completely get rid of js glue code by importing the static Reflect methods and a few functions like (a,b)=>a+b for the various operators, add a single array/object References to hold refs and you can do pretty much everything from wasm by mixing imported calls


> The idea of doing DOM manipulation in a language that is not Javascript

...is already possible, see for instance:

https://rustwasm.github.io/docs/wasm-bindgen/examples/dom.ht...

You don't need to write Javascript to access the DOM. Such bindings still call JS under the hood of course to access the DOM API, but that's an implementation detail which isn't really important for the library user.


While technically possible - the calls to javascript slow things down and you're never going to get the performance of just writing javascript in the first place, much less the performance of skipping javascript altogether.


The calls to JS are quite cheap, when trusting the diagrams in here it's about 10 clock cycles on a 2 GHz CPU per call (e.g. 200 million calls per second):

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

The only thing that might be expensive is translating string data from the language-specific string representation on the WASM heap into the JS string objects expected by the DOM API. But this same problem would need to be solved in a language-portable way for any native WASM-DOM-API, because WASM has no concept of a 'string' and languages have different opinions about what a string looks like in memory.

But even then, the DOM is an inherently slow API starting with the string-heavy API design, the bit of overhead in the JS shim won't suddenly turn the DOM into a lightweight and fast rendering system.

E.g. it's a bit absurd to talk about performance and the DOM in the same sentence IMHO ;)


Wasm could have had a concept of a string. I frequently mourn the rejection of the imo excellent stringref proposal. https://github.com/WebAssembly/stringref


wasm 3 has the JavaScript string built-in now according to TFA


That's a different thing. There is still no string type. JS string built-ins are a kludge for web targets only.


Just reimplement those JS string builtins in another host environment and provide it as a Wasm library. Stringref was basically just proposing pushing JS strings down into Wasm, which many in the CG saw as a big chunk of one specific platform just moving down a layer, into the engine.


Having used and implemented stringref and having seen the built-ins proposal I really think stringref is a much better developer experience and the CG is wrong. The built-ins are better than nothing but it's a terrible hack.


If your language and its compiler use JS String Builtins (part of Wasm 3.0) for their strings, then there is no cost to give them to JS and the DOM.


Fair enough, thanks for sharing!


Dart also has this and as you can see in the examples in the README the APIs look exactly the same as what you are used to in JavaScript but now are fully typed and your code compiles to WASM.

https://github.com/dart-lang/web


You don't get it.


... maybe you don't get it?

_Telling the browser how you want the DOM manipulated_ isn't the expensive part. You can do this just fine with Javascript. The browser _actually redrawing after applying the DOM changes_ is the expensive part and won't be any cheaper if the signal originated from WASM.


Don't get what, exactly?


Me too but e.g. Leptos makes the case that it isn't as important as some of us had imagined: https://youtu.be/4KtotxNAwME?si=cqprHdxU5oYAb0V_


> Direct DOM access doesn't make any sense as a WASM feature.

…proceeds to explain why it does make sense…


It's not a WASM feature, but would be a web browser feature outside the WASM standard.

E.g. the "DOM peeps" would need to make it happen, not the "WASM peeps".

But that would be a massive undertaking for minimal benefit. There's much lower hanging fruit in the web-API world to fix (like for instance finally building a proper audio streaming API, because WebAudio is a frigging clusterf*ck, and if any web API would benefit from an even minimal reduction of JS <=> WASM marshalling overhead it would be WebGL2 and WebGPU, not the DOM. But even for WebGL2 and WebGPU the cost inside the browser implementation of those APIs is much higher than the WASM <=> JS marshalling overhead.


so the feature does make sense, it’s just the implementation crosses a Conway’s law boundary

(I also want this feature, to drive DOM mutations from an effect system)


Sorta, in practical terms once WASI is ready the browsers can define a DOM world in WIT and maybe support components using it


> WebAudio is a frigging clusterf*ck

Out of curiosity, what issues do people have with WebAudio since audio worklets became widely supported?


Audio worklets are a step into the right direction for streaming audio, but for a simple audio-streaming API you don't need the complex node-based architecture of WebAudio, you just need a JS callback which writes samples into an ArrayBuffer.

With audio worklets this callbacks runs in a separate audio thread, and with the (deprecated) ScriptProcessNode this callback runs on the main thread.

E.g. a "good" web audio API replacement would only offer a callback that runs in a separate audio thread plus a convenience function call which allows to push small sample-packets from the main thread to the audio thread (at the cost of increased latency to avoid starving) - this push-function would basically be the replacement for ScriptProcessorNode.

In general, see here for a pretty good overview why WebAudio as a whole is a badly designed API: https://blog.mecheye.net/2017/09/i-dont-know-who-the-web-aud...

TL;DR: WebAudio's original design requires a lot of complexity and implementation effort for use cases that are not relevant to most of its users - and all that effort could be used instead to implement a much smaller and focused web audio API that covers actually relevant use cases.

Specifically for audio worklets: those mainly make sense when the entire audio stream generation can happen on the audio thread.

But if you need to generate audio on the main thread (such as in emulators: https://floooh.github.io/tiny8bit/), unless you want to run the entire emulator in the audio thread, you need an efficient way to communicate the audio stream which is generated on the main thread to the audio thread. For this you ideally need shared-memory multithreading, and for this you need control over the COOP/COEP response headers, and for this you need control over the web server configuration (which excludes a lot of popular web hosters, like Github Pages).

For this situation (generate sample stream on browser thread and communicate that to the audio thread) you're basically re-implementing ScriptProcessorNode, just less efficiently and limited by COOP/COEP. So at the very least ScriptProcessorNode should be un-deprecated.


WASM is a toy solution to an uninteresting problem without DOM access. It will continue to be a footnote until the. Maintainers get that through their fucking skulls.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: