Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

innerHTML can't be trusted: Does not always execute synchronously

Tags:

javascript

To see the problem in action, see this jsbin. Clicking on the button triggers the buttonHandler(), which looks like this:

function buttonHandler() {
  var elm = document.getElementById("progress");
  elm.innerHTML = "thinking";
  longPrimeCalc();
}

You would expect that this code changes the text of the div to "thinking", and then runs longPrimeCalc(), an arithmetic function that takes a few seconds to complete. However, this is not what happens. Instead, "longPrimeCalc" completes first, and then the text is updated to "thinking" after it's done running, as if the order of the two lines of code were reversed.

It appears that the browser does not run "innerHTML" code synchronously, but instead creates a new thread for it that executes at its own leisure.

My questions:

  1. What is happening under the hood that is leading to this behavior?
  2. How can I get the browser to behave the way I would expect, that is, force it to update the "innerHTML" before it executes "longPrimeCalc()"?

I tested this in the latest version of chrome.

like image 968
Jonah Avatar asked May 27 '13 15:05

Jonah


People also ask

Is innerHTML synchronous?

The innerHTML property actual does get updated synchronously, but the visual redraw that this change causes happens asynchronously. The visual rendering the DOM is asynchronous in Chrome and will not happen until after the current JavaScript function stack has cleared and the browser is free to accept a new event.

Why you shouldn't use innerHTML?

'innerHTML' Presents a Security Risk The use of innerHTML creates a potential security risk for your website. Malicious users can use cross-site scripting (XSS) to add malicious client-side scripts that steal private user information stored in session cookies.

Can scripts be inserted with innerHTML?

HTML specifies that a <script> tag inserted with innerHTML should not execute. For that reason, it is recommended that instead of innerHTML you use: Element.SetHTML() to sanitize the text before it is inserted into the DOM.

Why innerHTML is used in JavaScript?

The innerHTML property can be used to write the dynamic html on the html document. It is used mostly in the web pages to generate the dynamic html such as registration form, comment form, links etc.


1 Answers

Your surmise is incorrect. The .innerHTML update does complete synchronously (and the browser most definitely does not create a new thread). The browser simply does not bother to update the window until your code is finished. If you were to interrogate the DOM in some way that required the view to be updated, then the browser would have no choice.

For example, right after you set the innerHTML, add this line:

var sz = elm.clientHeight; // whoops that's not it; hold on ...

edit — I might figure out a way to trick the browser, or it might be impossible; it's certainly true that launching your long computation in a separate event loop will make it work:

setTimeout(longPrimeCalc, 10); // not 0, at least not with Firefox!

A good lesson here is that browsers try hard not to do pointless re-flows of the page layout. If your code had gone off on a prime number vacation and then come back and updated the innerHTML again, the browser would have saved some pointless work. Even if it's not painting an updated layout, browsers still have to figure out what's happened to the DOM in order to provide consistent answers when things like element sizes and positions are interrogated.

like image 65
Pointy Avatar answered Oct 05 '22 00:10

Pointy