Missing DOM mutation operations
@wycats has done a lot of investigation into what are the primitive DOM operations necessary to build up a tree, as part of https://github.com/whatwg/dom/issues/270.
This proposal so far has:
- append
- prepend
- remove
- insertBefore
(I think maybe append and prepend could be reduced to insertBefore in theory.)
It is missing the following:
- setAttribute
- removeAttribute
- setTextData (can be semi-emulated by removing the text node and inserting a new one, but that has slightly different semantics)
- attachShadow
There is also the following non-primitive but convenient operation:
- insertAdjacentHTML (can be emulated with
<template>.contentand insertBefore on the resulting DocumentFragment)
It leaves out setAttribute, etc. on purpose. Async append isn't a patch operation over the DOM, you can only insert/remove subtrees.
It should have:
append insertBefore remove innerHTML insertAdjacentHTML
It's quite complicated to do the async semantics over an attribute, text or shadow mutation. It would require us to double buffer the entire state in the engine.
That is to say, I think we can consider operations like that someday, but it's vastly more complicated than the insert/remove operations and it's not clear to me that we wouldn't need a different API surface for it.
Does this problem really need such as large API surface area? Aren't you really just saying: "Hey browser, give me a window of time where I can safely mutate this DOM subtree". Upon being granted that window, the user can perform any DOM mutation they wish (within this subtree scope), via the existing APIs.
window.requestMutation(element)
.then(element => element.innerHTML = ...);
This is a driveby comment, apologies if this has been discussed prior :)
No, the important bit here is that there's a lot of browser-side work that needs to be done in response to a mutation (rerunning selectors, figuring out styling, building the box tree, painting), and we don't want to hang the page's JS while we do it. The API presented here (ask the browser to do some async work, let me know when it's done) means that we can slice up the work into small chunks, interleaving them with page JS so it's never blocked for a large amount of time.
Your proposed API ("give me a window where I can make mutations without causing browser-side work until I'm done") doesn't let us do this - after the callback is called, there's still a potentially large chunk of work for the browser to do, and we have to do it immediately, before we run more JS (or if we do slice it up, we need to give the page a way to know when it's done, at which point you've devolved to our proposed API).
The "gimme a window" approach does help in some ways - in particular, it guarantees that interleaving read/writes won't trigger unexpected work - but that's also accomplished by our proposed API.