A bit OT, but setTimeout this reminds me of something I've wondered about.
Suppose you want to make some DOM change, and then when that change has actually been rendered so that the user can see it you want to do something else.
How do you actually wait for a DOM change to show up?
I first ran into this many years ago when I wanted clicking on a table column header to change the sorting of the table with the sort happening client side. The table was big enough that it could take a few seconds to sort, and this was before JavaScript had any true asynchronous computing mechanisms so the page would be unresponsive during the sort. I wanted to change some text near the table to "Sorting...please wait", do the sort, then clear the text.
A Stack Overflow answer said to use setTimeout of 0, and do the sort in the callback. In the pseudocode below, indentation means something done in the callback of the last function above with less indentation and the callback parameter will be omitted in the function that sets the callback.
It said that browsers all special cased 0 timeout and took it to mean run when the browser finishes all current pending processing, which included all DOM changes that JavaScript had made but that have not yet rendered.
I tested it on all the major browsers back then, on Windows, Linux, and Mac, and it indeed worked. Great.
But then a few years later I needed it again...and this time it did not work. Timeout 0 callbacks in Firefox were now always running the sort before the DOM updated. I tried double timeout 0:
That sometimes did the trick but sometimes did not.
Stack Overflow and some Googling suggested that the idea should still be sound, but rather than setTimeout one should use window.requestAnimationFrame (rAF) or window.requestIdleCallback (rIC).
On Firefox, those gave similar results to the double timeout 0. On Chrome, where single timeout 0 still worked, rIC worked the same as timeout 0, but rAF seemed to always run the callback code before the DOM update. On Safari timeout 0 and rAF worked, and Safari at the time did not have rIC. On Edge, both timeout 0 and rAF seemed to work, and edge did not have rIC.
I then tested double rAF and double rIC. Both of those seemed reliable on Firefox and Chrome. And since Safari, and Edge all have rAF, and even single rAF seems to work there, double rAF works on them too.
So, as of about 4 years ago when I last looked into this this seems the way to update the DOM, wait for the update to be visible, and then do something:
make_DOM_changes()
window.requestAnimationFrame()
window.requestAnimationFrame()
// DOM changes are visible
But is this actually guaranteed? Or just an accident of current implementations?
PS: here's a test page to play with this: https://pastebin.com/n26iVs7d The various buttons in the bottom section increment the count shown at the top then do a slow task. If it takes a second for the count to update then the slow task was not deferred until after the DOM update.
>Suppose you want to make some DOM change, and then when that change has actually been rendered so that the user can see it you want to do something else.
>How do you actually wait for a DOM change to show up?
I believe that use case would be covered by MutationObserver[0].
It makes sense, in theory the message should paint in the first animation frame but if you got in there before it you may sort before that happens. So you are requesting to wait for the frame after that. I'm sure there's some way it's not "guaranteed" because it seems nothing in front end is guaranteed without some asterisks, but this is the most logically correct solution I've seen.
Suppose you want to make some DOM change, and then when that change has actually been rendered so that the user can see it you want to do something else.
How do you actually wait for a DOM change to show up?
I first ran into this many years ago when I wanted clicking on a table column header to change the sorting of the table with the sort happening client side. The table was big enough that it could take a few seconds to sort, and this was before JavaScript had any true asynchronous computing mechanisms so the page would be unresponsive during the sort. I wanted to change some text near the table to "Sorting...please wait", do the sort, then clear the text.
A Stack Overflow answer said to use setTimeout of 0, and do the sort in the callback. In the pseudocode below, indentation means something done in the callback of the last function above with less indentation and the callback parameter will be omitted in the function that sets the callback.
So that Stack Overflow answer said do this.
It said that browsers all special cased 0 timeout and took it to mean run when the browser finishes all current pending processing, which included all DOM changes that JavaScript had made but that have not yet rendered.I tested it on all the major browsers back then, on Windows, Linux, and Mac, and it indeed worked. Great.
But then a few years later I needed it again...and this time it did not work. Timeout 0 callbacks in Firefox were now always running the sort before the DOM updated. I tried double timeout 0:
That sometimes did the trick but sometimes did not.Stack Overflow and some Googling suggested that the idea should still be sound, but rather than setTimeout one should use window.requestAnimationFrame (rAF) or window.requestIdleCallback (rIC).
On Firefox, those gave similar results to the double timeout 0. On Chrome, where single timeout 0 still worked, rIC worked the same as timeout 0, but rAF seemed to always run the callback code before the DOM update. On Safari timeout 0 and rAF worked, and Safari at the time did not have rIC. On Edge, both timeout 0 and rAF seemed to work, and edge did not have rIC.
I then tested double rAF and double rIC. Both of those seemed reliable on Firefox and Chrome. And since Safari, and Edge all have rAF, and even single rAF seems to work there, double rAF works on them too.
So, as of about 4 years ago when I last looked into this this seems the way to update the DOM, wait for the update to be visible, and then do something:
But is this actually guaranteed? Or just an accident of current implementations?PS: here's a test page to play with this: https://pastebin.com/n26iVs7d The various buttons in the bottom section increment the count shown at the top then do a slow task. If it takes a second for the count to update then the slow task was not deferred until after the DOM update.