This example actually illustrates why I find much of the new ECMAScript to be pointlessly cryptic and needlessly bloated; and why I find this whole "Virtual DOM" thing to be complete nonsense based on nothing more than lies and disinformation.
There seems to be this paranoid unfounded claim being circulated that working directly on the DOM is 'slower' or that there's some sort of 'render' overhead. If you do it RIGHT there is no such thing since the browser's rendering engine does not render changes to the DOM until scripting execution is released!.
If anything, by creating and maintaining a "virtual DOM" -- or as it should be called and was for the first decade and a half of JavaScript in the browser a "document fragment" -- means doubling down on memory use (since you have two copies), doubling down on processing and render time since you have to make the live and the copy, and in general taking something ridiculously simple -- DOM Manipulation -- and making it as painfully difficult to do as possible.
... and over what? A bald-faced LIE about some sort of fantasy-land render overhead that you're going to have anyways since you have to copy it to the live DOM sooner or later?
This is part of what I meant a year or so ago when I asked "Are people just afraid of the DOM?" Even when they "use it" they don't really use it, or understand it...
I mean... well let's use your example. Rather than maintaining a second "virtual" copy (aka a document fragment), you build it on the DOM, and when you want to change values you do so on the DOM. Element.removeChild isn't rocket science, nor is textNode.data anything too complicated to deal with. If you made the count as its own text node, all you'd have to write is the count to textNode.data. If you have more than your new count in images truncate the difference from the end. If your new count is more than the number of live images, just appendChild that many images. It WILL be faster than all that pointless "diff" nonsense and "Virtual DOM" waste that just introduces overhead for nothing.
Let's start with three simple little helper functions, treat them as equivalent to your various dependency hell 'include'.
function make(tag, parent, attr, content) {
tag = d.createElement(tag);
if (attr) for (var i in attr) tag.setAttribute(i, attr[i]);
if (content) node_add(tag, content);
if (parent) parent.appendChild(tag);
return tag;
}
function node_add(e, newNode) {
return e.appendChild(
'object' == typeof newNode ? newNode : d.createTextNode(newNode)
);
}
function node_stripEnd(e, count, from) {
if (!from) from = e.lastChild;
while (from && count--) {
var next = from.previousSibling;
e.removeChild(from);
from = next;
}
}
"make" just makes elements applying and placing them as needed. (way gutted down from my 'proper' make routine which is far more powerful). "node_add" is just a shorthand for appendChild that lets us not worry or think about if we're adding a new DOM node or just plain text. "node_stripEnd" lets you strip children off the end of an element, or working upwards from (and including) a starting element. We don't need that latter functionality, but this is a straight cut and paste from my cheatsheet.
Then our actual logic:
var
count = 0,
appDIV = make('div', d.body, { id : 'app' }, 'The current count is '),
countText= node_add(appDIV, count),
cloneIMG = make('img', false, {
src : 'media.giphy.com/media/cuPm4p4pClZVC/giphy.gif'
});
function updateApp() {
var newCount = Math.floor(Math.random() * 10);
if (newCount < count) {
node_stripEnd(appDIV, count - newCount);
count = newCount;
} else while (count < newCount) {
count++;
node_add(appDIV, cloneIMG.cloneNode());
}
countText.data = count;
}
updateApp();
setInterval(updateApp, 1000);
No goofy hard to follow arrow functions, no need for let/const (at most I'd wrap it in a SIF / SEF / IIFE / PickANameForItAlready) since lifting actually reduces the memory thrashing, etc, etc.
We set our count to zero so we can track it, make a DIV#app directly on BODY (since it's a scripting only element it has no business in the markup) with "The current count is " text already attached. Then making the countText its own independent textNode lets us just "countText.data=" when it comes time to update the count. Finally we create an image node to clone since for now we're just using all the same image.
The update function as a standalone can be called directly and timeout, giving us our initial render of counted elements and the interval refresh. All it needs to do is pick a new count and if there are less new ones than old ones we strip off the excess, otherwise we add the difference. Finally just update the count shown in the textNode to match.
Call updateApp to draw some children on initialization, set the timeout to update, done.
A fraction the code and logic, dozens of times easier to follow, runs way faster, and works all the way back to IE 5.x
Live demo here:
cutcodedown.com/for_others/jasonYu
That is why I find this whole "Virtual DOM" thing to be pointless, wasteful, and based on lies. I fail to understand -- apart from broken/bad methodology and/or a complete failure to grasp how browser render engines and JS interact -- how this fairy-tale nonsense about "render time" comes into it, how directly working with the live DOM is somehow magically "Bad", what people mean when they talk about "Side effects" since in most cases what they are talking about is stuff I expect to happen, want to happen, and as such aren't side effects it's what they're flipping for, etc, etc, etc.
I'm either missing something painfully obvious, or my way of looking at solving problems is radically different from RoW. (rest of world)
Though I really think if JS app developers spent more time thinking like website developers, they'd realize how foolish so many of these approaches to doing things are.