As a hardcore JavaScript developer I welcome this tech for a couple reasons. For one thing, it's undeniably a significant step forward for Web Platform as a whole. For another, now people can struggle with the peculiarities of the said Web Platform with their own languages. The legitimate grievances associated with JS over the years were due to the browser APIs and first of all DOM, which wasn't designed for JS to begin with and later just accumulated problems for the sake of backwards compatibility.
On an upside, with WASM browsers can potentially save a snapshot of the compiled code to speed up re-runs. I recall the idea was promoted back when Dart was expecting to get its own VM, and one of the things that it would be capable of was this snapshot using.
Even if you can get everyone to agree on one canonical CDN (you can't), you also need to get everyone to agree on one version of the file at the CDN.
Plus cache sizes on most platforms are laughably small (a heavy page can completely blow out your cache on mobile devices).
IIRCthere was a "study" while back that found by using the most common CDN at the time to host jQuery, you only got like a 5% cache hit rate. This was because of multiple CDNs, multiple versions, multiple ways to reference the version (1.2.3 vs 'latest'), and http/HTTPS.
In my past experience, we had more trouble with people blocking our CDN via corporate networks or something.
The firewall issue is always going to be a problem on corporate networks. I don't think we're ever realistically going to get away from having to self-serve dependencies if you want to ensure that things are going to work, particularly if it's software that is deployed in on-premise, internal servers.
And while updates every 6 weeks might seem crazy to you, unless we just don't version the links (which seems like a terrible idea), even simple bugfxes blow the whole system.
Plus CDN hosted systems come with a bunch of other downsides. Lack of http2 pushing, tree shaking and bundling doesn't work, being able to compile with your own settings, and more.
CDNs aren't the solution here, something like using service worker and/or an "install" process for web apps will solve all of these and more.
First of all, it's dangerous because you could "probe" the user's cache cross-domain by offering files with a specific checksum and seeing if they take it or not. Letting evil-example.com figure out if you have visited pornhub recently by offering up their javascript file with the subresource hash attached and seeing if you download it is a massive privacy violation and can cause issues much worse than just knowing you were on pornhub.
Second, Cache sizes are already too small, and while a content-addressable-cache might help with that a bit, it won't really change all that much. You'll still have 100 versions of jquery out in the wild at any time, you'll still have 10,000 different versions of react bundled with other things. You'll still have the version with a UTF-8 BOM and one without, or one with \n and one with \r\n.
Finally, (and this one is just my opinion) it's a solution that encourages worse behavior. It's going to be easier to include that 300kb of jquery when you think that your users will have it cached already. And that just "loosens the belt" around an area where we should be cutting back. Now users that are arriving for the first time will get a significantly worse experience, and that is the starting to go against a fundamental strength of the web, that you can get the same experience on any device, anywhere, any time, whether it's your computer, your cousin's desktop, your friend's phone, or your damn car. Making devices that don't have that in their cache download a massive "basically binary" blob before they can use it is against what the web is, and content-based caching really encourages the behavior of including entire libraries (so they'll be cached) instead of compiling down only the code you need.
While most of this can be mitigated, this just isn't something that's sorely needed. There is an MDN document floating around somewhere that they were talking about something like this, but I can't seem to find it right now.
Of course, we move from the beauty of no-install software on the web back to runtime installing but...maybe it would be better?
Obviously it can be nice for organization, but that should really fall more on the individual to decide than the spec.
Back to the question:
Traversal: Historically we had 4 methods to get an element: by its id, name, tag, and class; yet there was no general method to get an element by value of its attributes until Selectors API brought querySelector. IMO it was one the most important things that pushed the community towards jQuery back in the day.
Manipulation: Up until recently one couldn't remove an element without referencing its parent, that is, you have to use removeChildNode, or replace, or innerHTML, or other methods of the parent. Now they added .remove() that is only supported in the evergreen browsers. Replacing or inserting nodes operates on the same principles and is a hell of its own that makes people opt for re-generating nodes instead of shuffling the existing ones.
Generation: For years now we have been relying on non-standard innerHTML for element generation because the only way DOM allows to do it is to create each element with createElement and then set attributes one by one. It's a ridiculously low level api considering our use cases. Hence, we got the whole templates/jsx movement today.
Modularity: Ain't there. In order to truly "componentize" our apps we have to wait for something like Shadow DOM because there is no way to guaranty that one part of the page won't affect the other in today's DOM.
All in all, DOM wasn't meant for what we are trying to use it today and for a long time it has been playing catch with browsers implementing ad-hoc solutions to new problems.
Because I look at all the GUI toolkits out there (and in the last twenty years I've used a LOT of different ones), and none of them are idealistically "good". I don't see anything particularly special about other toolkits that makes DOM look particular bad. In fact, I tend to think of DOM as being pretty good in comparison, if only for the fact that it works on everything.
"createElement and then set attributes one by one" is no different than any other toolkit. They pretty much all have a simple, static editor syntax for doing bulk element creation and attribute setting, and then a verbose API for dynamic element creation. It's low level because your use case is not the only use case it needs to support. I've seen--and built--a bunch of systems that have tried to simplify it and it always loses something in translation.
So maybe you're complaint isn't with DOM. Maybe you just don't like user interface programming in general.
That's because my whole point was to elaborate on the statement I made in the first comment:
>The legitimate grievances associated with JS over the years were due to the browser APIs and first of all DOM,
People who were complaining about web dev and JS over the years were mostly doing it because of the browser APIs and DOM, hence my recollection of recent history. And of course I do point out what was fixed, and I said from the start that it's far better now than it was before. I'm rooting for VanillaJS after all.
I cannot comment on other GUI toolkits since I don't work with them. You may be right that they too are low level, and I wholeheartedly you're right about DOM being better, because I hope DOM with Web Platform replaces them all one day. That doesn't exempt DOM from criticism though.
Technically DOM still doesn't have API for bulk element creation since innerHTML/insertAjacent comes as a separate API which is still a working draft. But that's just details.
There is another problem somewhat related to DOM being low level. Although it has to do with the browser implementations rather than the standard, it's still a problem for the end user, and the user is going to blame it on the web/JS being bad in general. That is performance. As it was mentioned here, DOM is separated from JS engine in browsers. Calls to DOM from JS are a lot more expensive than calls inside the engine. This gave rise to the whole Virtual DOM movement we see taking over the web dev. It's not just the verbosity of low level DOM that pushes people towards React and such, but the fact that at the end of the day their approach of mimicking DOM in the engine and limiting the DOM calls turns out to be more performant that the low level manipulations we do directly on the DOM.
Consider the following scenario. You have two handlers on an event that both change the DOM and may result in cancelling each other. With the "raw" DOM you'll end up calling DOM at least twice (and changing it twice if no debouncing is used), whereas Virtual DOM both times calls to, well, its "virtual" DOM (which is a lot cheaper) and by the time it gets to its next cycle of updating the "real" DOM it may not need to change anything or do it once. These optimizations are hard to implement without resorting to a virtual DOM of one sort or another.
Sort of. Calls to DOM from JS are a few dozen machine instructions for the call itself in modern browsers; a little more if lots of arguments are involved. The slowness is what the DOM implementation actually has to _do_ as a result of the call. If you write a loop in which you repeatedly modify styles and then ask for geometry information, then the only options an implementation has are to provide stale geometry information (the virtual DOM approach!) or end up with that loop being a lot slower than asking for all the geometry information up front and then doing your modifications.
We can have a useful discussion about whether it should be possible to ask for stale geometry information, but that has nothing to do with calls from JS into the DOM per se; a DOM implemented in JS but exposing the same API as the current DOM would have _exactly_ the same problem in that regard.
What got me first thinking about the cost of DOM calls were benchmarks we did back when we were building polyfills for IE6-IE8 to support new HTML5 APIs. One example in particular--mimicking data attributes. Our lib would hold a mapping between DOM elements and attached data attributes (as simple objects) and it would be significantly faster than using native element.dataset. While dataset isn't as simple as plain JS object, it's not much complicated either, and to my knowledge changing it doesn't cause reflows or repaints, so I expected it to be slower but not very much; hence, I concluded that the additional speed came from avoiding the DOM call itself. Since then I've been cautious about DOM and tried to cache whatever came from it and was supposed to be used repeatedly.
So you have to implement it as a Proxy, so it can capture arbitrary property assignments, including for properties it doesn't have yet, and do the corresponding setAttribute calls. Unfortunately, once you're a Proxy your gets end up somewhat slow too. Partly this is because JITs haven't optimized proxies that much, and partly it's because they're rather hard to optimize in the best of circumstances.
I expect that the actual implementations of dataset are not as fast as they could be if they used scripted and inlinable proxy handlers _and_ the JITs had implementations for those. But there's still a lot more work involved in dataset than a plain object, especially if you have a small number of property names in practice so the plain object doesn't have to convert to dictionary mode or anything like that.... Even if dataset were implemented on top of a pure-JS DOM implementation (which exist), it would be a lot slower than just a simple object, unfortunately.
[1]https://jsperf.com/dataset-vs-getattribute-and-setattribute/...
But note that in microbenchmarks you are likely to get some confusing effects. For example, in Firefox this microbenchmark:
document.getElementById('test').getAttribute('data-set')
will get optimized as follows:1) getAttribute is known to be side-effect free when called with a string argument, its return value is not used, the call can be dead-code eliminated.
2) getElementById is known to be side-effect free when called with a string argument, its return value is not used after step 1, the call can be dead-code eliminated.
3) The get of the "document" property is known to be side-effect free, its return value is not used after step 2, the get can be dead-code eliminated.
So in the end the microbenchmark is measuring how fast the browser can increment a loop counter, and that only because we haven't bothered to try dead-code eliminating that. That's why you get numbers in the billions of operations per second range (comparable to the CPU clock speed; always a dead giveaway that your thing got optimized out). ;)
Note that Firefox will also perform loop-hoisting on all of the above if possible, so even if the return value were assigned somewhere that would not matter: the whole thing would just get hoisted out of the loop.
The setAttribute and "dataset.set = stuff" benchmarks don't have these problems, because those operations are clearly not side-effect free. A sufficiently advanced JIT might be able to determine that earlier iteration assignments are dominated by later ones and eliminate them, but now we're talking quite hard work on the part of the browser.
While we are on the subject, can I ask if there are any performance advantages of using data attributes over custom attributes for storing data in an element? In other words, can adding non-standard attributes to an element cause any deoptimizations? I know that JS engines use hidden classes/object shapes to optimize JS objects, I assumed something similar might be the case for DOM elements, in that case adding non-standard attribute must mean deoptimization.
Every node has a reference to it's parent.
What's the problem with node.parentElement.removeChild(node)?
Being counter-intuitive and verbose. It's but one example of such peculiarities that makes DOM hard to grasp for beginners.
It's node.parentNode.removeChild(node). And the fact that this is even a mistake that can be made, and is made by people all the timem is part of the problem!
"node.remove()" is a lot harder to screw up.
Edit: Looks like WebAssembly is more low level than asm.js, and is actually closer to real assembly, whereas asm.js is more akin to C.
For a simple example...
i = i|0;
This is valid JS, but a JS engine designed to use asm.js optimizations can look at the bitwise OR with 0 before the script even runs and realize that i must be an integer in that block of code, so it can use more-efficient integer operations instead of float ones.Yup! Thats the plan for web assembly! Write in what you want, compile to browser-supported format, deploy.
It is intended for C and C++ developers to be able run their code in a performant way on the web.
[1] http://teavm.org/ [2] https://www.reddit.com/r/programming/comments/5899ln/teavm_j...
Users don't care which one you use, so it won't make sense to switch to WebAssembly until there's a significant performance benefit and the code size issues are solved.
Which can be useful, but it can also be bad if your languages model doesn't map perfectly to JS's (this is an issue already with JS-hosted versions of a number of languages that introduces incompatibilities with non-JS-hosted implementations.)
Unless you go 100% no-js you are still going to need to interact with it, and even if you do completely remove JS in your stack, the DOM APIs are still geared toward JS, and work in ways that make sense to JS.
AFAIK WASM literally aims to be a "universal web bytecode", and they hope to eventually add multi-threading, GC and DOM access. Of course the exact implementation details might differ from e.g. your local Java runtime vis a vis GC and threading timings and such.
But for example in a distant future each browser's JavaScript runtime could be just an interpreter that internally emits WASM. And there should not be any reason why you could not compile most Java / C# code to WASM once threads and GC are added.
No where does it say that it's intended to be a universal bytecode.
There's a whole Wiki page dedicated to GC: https://github.com/WebAssembly/design/blob/master/GC.md
Sounds like they aim to implement only GC primitives to allow emulating a wide variety of different VMs.
You can get rid of JS's shortcomings for years now with compilation. That's not really the goal here. What I see here is low level access for raw power. Most of the JS apps don't really need it.
Edit: I take it back. According to this note, I don't see what would stop anyone avoiding JS at all. http://webassembly.org/docs/gc/#webidl-integration
Once you can reach the DOM API directly from WA code, JS is redundant for you can use for example C# to build apps.
I hate to sound alarmist, but we might look back at 2012-16 as the years when frontend tooling was easy :)