Hello,
I tried to find the code for innerHTML
and appendChild
in Chromium in the hopes that the explanation will be something simple.
I think I'm completely outmatched even trying to read this code... but I'm just posting here since this thread seems to have been silent for a long time and I can note down whatever I find here.
I would like to compile this code and step through it, but right now I don't have a computer that will be able to pull this off I think. And I don't want to destroy the machine I have that I use to follow HMH on.
-
The code for innerHTML is in this file. You can search for setInnerHTML
. https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/dom/element.cc
-
AppendChild
is defined in this file. https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/dom/node.cc;l=730?q=append&sq=&ss=chromium%2Fchromium%2Fsrc:third_party%2Fblink%2Frenderer%2Fcore%2Fdom%2F
Here is the code for appendChild
im seeing:

which then calls the following function (I think):

which is in this file https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/dom/container_node.cc
So we see there are a bunch of checks going on here.
And this is the code for innerHTML
:
which should just call setTextContent
.

And we see here that it eventually just calls the AppendChild
function. So I am stumped! To me this seems to indicate that they should run in the same time... so is it possible that actually its the javascript loop that slows the thing down? If that is the case... I can't think of a way to write a test that will do several appends without executing javascript. But I guess if I am right in the assumption that its the javascript that is slowing it down then, just doing it without javascript should make it fast. Maybe NaCl in chrome has a way to check this?
If I could compile chromium, i could maybe hack it to write a function that calls appendchild in a c++ loop and expose it as a separate function on the dom itself. And then I guess it will constitute proof that it is the javascript loop doing the appends that is the issue.
On the issue of why pushing to a javascript array is faster. As far as I know javascript arrays will be created and handled by v8
and dom and its operations will be handled by blink
as noted above. Although I have no clue how to figure out if those are two different threads or somehow running in the same thread. But given that the two codes are so vastly separated in the codebase of chrome I suppose it won't be a fair comparison to accept an array push as some kind of metric about how fast it can go. Although I don't really understand the code above, I think this code is completely different from the code that handles arrays, which I have seen in v8's codebase in the past but not screenshotting here. And I don't know how we can just expect them to have the same max speed.
Looking at all these things that go on to make a div and having done web programming for 7 years using frameworks like react and vue though... we are just trying to render stuff. We should be just rendering them on the canvas. However, if we do that our code will still be going through js or wasm. And then we will probably end up being slow anyway. My only hope is the simd in webassembly spec now. I have only yesterday reached episode 112 in HMH which is the beginning of SIMD. And I hope there is some magic in there that will let me write canvas based ui's without using the dom. I pray I don't get stuck with an unsolvable problem... because I really really want to write C and ship it on the web and have it as fast or faster than react or other similar frameworks.
Afterthought: If I was writing a javascript interpreter I would at least write something that can optimize simple loops. And I know that v8 has gone, as Casey Muratori will say, "full banana cakes" with trying to optimize javascript on the fly. So I would not be surprized if we are not even able to write array pushes in a loop that don't end up getting optimized "within an inch of their lives" by v8. And well Im not that smart but the simplest optimization i can think of when looking at a javascript loop like this:
for (let i = 0; i < NUM_ELEMENTS_TO_INSERT; i++) {
results.push(`Case ${caseNumber}, element ${i}`)
}
would be to simply hoist it into pure C and throw the O2 flag at it. Loops like this should be pretty easy for me to convert to plain C if I have written the whole interpreter... and I'd just do that.