4 ms·
I don't understand the purpose of setTimeout(/* ... */, 0) (or setImmediate). If I want a function to execute immediately I will call it directly, not via setTi
by dandare 8y ago
I don't understand the purpose of setTimeout(/* ... */, 0) (or setImmediate). If I want a function to execute immediately I will call it directly, not via setTimeout(0). What am I missing?
- Doxin 8y agosetTimeout(0) doesn't call the function immediately. It will call the function at the next opportunity. Usually this means that for example that element you added to the DOM has now rendered.
- dandare 8y agoElement added to the DOM is not rendered immediately? for instance, this works as expected, the button will be blue: function myFunction() { var btn = document.createElement("BUTTON"); var t = document.createTextNode("CLICK ME"); btn.appendChild(t); document.body.appendChild(btn); btn.style.color = "blue" }
- tzs 8y agoThat does not appear to be the case in Firefox (62.0). Using dandare's blue button adding function from his reply to your comment here is some test code: function myFunction() { var btn = document.createElement("BUTTON"); var t = document.createTextNode("CLICK ME"); btn.appendChild(t); document.body.appendChild(btn); btn.style.color = "blue"; } function slow(n) { console.log('slow called'); let s = 0; for (let i = 0; i < n; ++i) s += 1.00000001; console.log('slow:' + s); return s; } function callMyFunction(to) { myFunction(); setTimeout(function () {slow(5000000000);}, to); } The argument to slow() in the timeout function, 5000000000, causes it to take about 5 seconds on my system, long enough to easily tell if the button has rendered before slow runs. In Chrome, callMyFunction(0) results in the blue button showing up, then 'slow called' in the log, then 5 seconds later slow() finishes. I did this several times and the results were the same every time. In Firefox, it results in 'slow called' in the log, then 5 seconds later slow finishes and the blue button shows up. Several tries with callMyFunction(0) resulted in no instances of the rendering being done before the timeout function was called. I had to bump the argument to callMyFunction up to 35 to get the rendering to happen consistently before the timeout function (10 out of 10 times). It mostly completed before the timeout at 34, but not always. This is surprising to me, because the impression I got when I looked into this a few years ago on Stackoverflow and other web sites was the setTimeout(0) was a reliable way to make sure that all DOM changes were rendered. My test procedure: open browser. Open inspector. Paste the above code into the console. invoke callMyFunction from the console while watching the screen for the button and the log for slow's messages. I wonder if JavaScript invoked from the console might have some different rules for rendering timing? Edit: nope, it has nothing to do with the console. I tried the above, but invoked by a click on a page instead of from the console, and the results are the same.
- tzs 8y agoI've done some experiments of the form 1. Make a visible change to the DOM, 2. wait somehow for that hopefully to become visible, 3. call a slow compute task I tried the following methods for waiting: 1. setTimeout (various values) 2. window.requestAnimationFrame 3. windows.requestIdleCallback 4, 5, 6. doubled forms of the above three methods. By doubled I mean that instead of, say, calling the slow function from the requestAnimationFrame callback, that callback does another requestAnimationFrame, and it is the callback for that second requestAnimationFrame. Here is a test program that puts up a page with a count on top, a couple fields to give the timeout for setTimeout and how slow the slow task should be, and buttons to try the aforementioned delay methods (also one to call direct without a delay). Clicking the button will increment the counter, invoke the delay, and then invoke the slow function. It also prints timing information on when various events happened and when various things were called (overwritten for each test), and also a log below that of events and slow task timing. https://pastebin.com/n26iVs7d https://pastebin.com/n26iVs7d Results follow. === Firefox 62.0 (Mac, Windows) Double requestAnimationFrame and double requestIdleCallback seem to be reliable. I've never seen the slow task start before the counter display has updated. Single requestAnimationFrame and requestIdleCallback usually run the slow task before the counter display has updated, but every so often the display updates first. On Windows, single requestIdleCallback seems more likely to do the update first than on Mac. setTimeout(0) seems to always runs the slow task before the display updates. Double setTimeout(0) is similar to single requestAnimationFrame or requestIdleCallback. Mostly does not update until after the slow task, but occasionally does update first. === Chrome 68.0.whatever_is_current (Mac) setTimeout(0) seems to always update display before running slow task. Single requestIdleCallback, same as setTimeout(0). Single requestAnimationFrame seems to always run the slow task before display update. Double requestAnimationFrame seems to always update the display before the slow task. === Safari (Mac) setTimeout(0) and single requestAnimationFrame update display before slow task. Does not have requestIdleCallback. === Edge (Windows) No requestIdleCallback. setTimeout(0) and single requestAnimationFrame seem to always update display before slow task runs. Looks like double requestAnimationFrame is the way to go.
- perilunar 8y agoIn the case of animations, if you call the main animation loop from inside the loop you will quickly get a "too much recursion" / "maximum call stack size exceeded" error. e.g. function main() { // do animation stuff main(); } Will throw an error. If you do the following: function main() { // do animation stuff window.setTimeout(main, 0); } You wont get the error, because main() is being called by window instead, so is not recursive. (window.requestAnimationFrame is usually better for animation though).