By Dan Lew


2009-04-22 21:46:08 8 Comments

I've recently run into a rather nasty bug, wherein the code was loading a <select> dynamically via JavaScript. This dynamically loaded <select> had a pre-selected value. In IE6, we already had code to fix the selected <option>, because sometimes the <select>'s selectedIndex value would be out of sync with the selected <option>'s index attribute, as below:

field.selectedIndex = element.index;

However, this code wasn't working. Even though the field's selectedIndex was being set correctly, the wrong index would end up being selected. However, if I stuck an alert() statement in at the right time, the correct option would be selected. Thinking this might be some sort of timing issue, I tried something random that I'd seen in code before:

var wrapFn = (function() {
    var myField = field;
    var myElement = element;

    return function() {
        myField.selectedIndex = myElement.index;
    }
})();
setTimeout(wrapFn, 0);

And this worked!

I've got a solution for my problem, but I'm uneasy that I don't know exactly why this fixes my problem. Does anyone have an official explanation? What browser issue am I avoiding by calling my function "later" using setTimeout()?

17 comments

@Vladimir Kornea 2014-07-26 00:30:21

There are conflicting upvoted answers here, and without proof there is no way to know whom to believe. Here is proof that @DVK is right and @SalvadorDali is incorrect. The latter claims:

"And here is why: it is not possible to have setTimeout with a time delay of 0 milliseconds. The Minimum value is determined by the browser and it is not 0 milliseconds. Historically browsers sets this minimum to 10 milliseconds, but the HTML5 specs and modern browsers have it set at 4 milliseconds."

The 4ms minimum timeout is irrelevant to what is happening. What really happens is that setTimeout pushes the callback function to the end of the execution queue. If after setTimeout(callback, 0) you have blocking code which takes several seconds to run, the callback will not be executed for several seconds, until the blocking code has finished. Try this code:

function testSettimeout0 () {
    var startTime = new Date().getTime()
    console.log('setting timeout 0 callback at ' +sinceStart())
    setTimeout(function(){
        console.log('in timeout callback at ' +sinceStart())
    }, 0)
    console.log('starting blocking loop at ' +sinceStart())
    while (sinceStart() < 3000) {
        continue
    }
    console.log('blocking loop ended at ' +sinceStart())
    return // functions below
    function sinceStart () {
        return new Date().getTime() - startTime
    } // sinceStart
} // testSettimeout0

Output is:

setting timeout 0 callback at 0
starting blocking loop at 5
blocking loop ended at 3000
in timeout callback at 3033

@Salvador Dali 2014-10-09 01:14:04

your answer does not prove a thing. It just shows that on your machine under in a specific situation computer throw you some numbers. To prove something related you need a little bit more than few lines of code and a few numbers.

@Vladimir Kornea 2014-10-09 01:22:56

@SalvadorDali, I believe my proof is clear enough for most people to understand. I think you're feeling defensive and haven't made the effort to understand it. I'll be happy to attempt to clarify it, but I don't know what you're failing to understand. Try running the code on your own machine if you suspect my results.

@Salvador Dali 2014-10-09 01:26:49

I will try to make it clear for the last time. My answer is clarifying some of the interesting properties in timeout, interval and is well supported by valid and recognizable sources. You made a strong claim that it is wrong and pointed to your piece of code which for some reason you named a proof. There is nothing wrong with your piece of code (I am not against it). I am just telling that my answer is not wrong. It clarifies some points. I am going to stop this war, because I can not see a point.

@Willem van der Veen 2018-09-15 09:12:40

The problem was you were trying to perform a Javascript operation on a non existing element. The element was yet to be loaded and setTimeout() gives more time for an element to load in the following ways:

  1. setTimeout() causes the event to be ansynchronous therefore being executed after all the synchronous code, giving your element more time to load. Asynchronous callbacks like the callback in setTimeout() are placed in the event queue and put on the stack by the event loop after the stack of synchronous code is empty.
  2. The value 0 for ms as a second argument in function setTimeout() is often slightly higher (4-10ms depending on browser). This slightly higher time needed for executing the setTimeout() callbacks is caused by the amount of 'ticks' (where a tick is pushing a callback on the stack if stack is empty) of the event loop. Because of performance and battery life reasons the amount of ticks in the event loop are restricted to a certain amount less than 1000 times per second.

@staticsan 2009-04-23 00:14:17

This works because you're doing co-operative multi-tasking.

A browser has to do a number of things pretty much all at once, and just one of those is execute JavaScript. But one of the things JavaScript is very often used for is to ask the browser to build a display element. This is often assumed to be done synchronously (particularly as JavaScript is not executed in parallel) but there is no guarantee this is the case and JavaScript does not have a well-defined mechanism for waiting.

The solution is to "pause" the JavaScript execution to let the rendering threads catch up. And this is the effect that setTimeout() with a timeout of 0 does. It is like a thread/process yield in C. Although it seems to say "run this immediately" it actually gives the browser a chance to finish doing some non-JavaScript things that have been waiting to finish before attending to this new piece of JavaScript.

(In actuality, setTimeout() re-queues the new JavaScript at the end of the execution queue. See the comments for links to a longer explanation.)

IE6 just happens to be more prone to this error, but I have seen it occur on older versions of Mozilla and in Firefox.


See Philip Roberts talk "What the heck is the event loop?" for more thorough explanation.

@David Mulder 2012-06-04 14:30:30

'The solution is to "pause" the JavaScript execution to let the rendering threads catch up.' Not entirely true, what setTimeout does is add a new event to the browser event queue and the rendering engine is already in that queue (not entirely true, but close enough) so it gets executed before the setTimeout event.

@staticsan 2013-10-16 06:36:51

Yes, that is a much more detailed and much more correct answer. But mine is "correct enough" for people to understand why the trick works.

@jason 2013-11-01 13:34:15

@DavidMulder, does it means browser parse css and rendering in a different thread from javascript execution thread?

@David Mulder 2013-11-05 13:37:47

Nope, they are parsed in principle in the same thread otherwise a few lines of DOM manipulation would trigger reflows all the time which would have an extremely bad influence on the speed of execution.

@mvmn 2015-08-19 11:18:25

There are some JS errors in IE8 that seem to ignore try/catch. Don't ask me how this happens - I still can't figure it out. Seems like it's related to low-level components like ActiveX or whatever does gradient filters in ProgressiveIE. There is but one way to ignore those errors - wrap the call in setTimeout with 0 timeout - this way setTimeout callback is essentially run in different thread, and on error that thread gets interrupted, but the one that called setTimeout continues to work. So here's +1 reason to use setTimeout with 0 timeout in IE.

@davibq 2015-11-09 23:01:56

This video is the best explanation to why us setTimeout 0 2014.jsconf.eu/speakers/…

@Dmitry 2016-08-15 04:46:30

I just had an SVG problem where I wanted to remove an svg element and then add it and then do a bunch of things. The problem was that these "bunch of things" were being done as the remove/add occured, and wrapping the rest of the function in setTimeout 0 made the "transitions" work again. Very strange.

@Christian Jensen 2019-04-02 16:48:06

@davibq I would also highly suggest this fantastic (and humorous) presentation: youtube.com/watch?v=cCOL7MC4Pl0

@DanielSmedegaardBuus 2018-06-05 06:26:31

Both of these two top-rated answers are wrong. Check out the MDN description on the concurrency model and the event loop, and it should become clear what's going on (that MDN resource is a real gem). And simply using setTimeout can be adding unexpected problems in your code in addition to "solving" this little problem.

What's actually going on here is not that "the browser might not be quite ready yet because concurrency," or something based on "each line is an event that gets added to the back of the queue".

The jsfiddle provided by DVK indeed illustrates a problem, but his explanation for it isn't correct.

What's happening in his code is that he's first attaching an event handler to the click event on the #do button.

Then, when you actually click the button, a message is created referencing the event handler function, which gets added to the message queue. When the event loop reaches this message, it creates a frame on the stack, with the function call to the click event handler in the jsfiddle.

And this is where it gets interesting. We're so used to thinking of Javascript as being asynchronous that we're prone to overlook this tiny fact: Any frame has to be executed, in full, before the next frame can be executed. No concurrency, people.

What does this mean? It means that whenever a function is invoked from the message queue, it blocks the queue until the stack it generates has been emptied. Or, in more general terms, it blocks until the function has returned. And it blocks everything, including DOM rendering operations, scrolling, and whatnot. If you want confirmation, just try to increase the duration of the long running operation in the fiddle (e.g. run the outer loop 10 more times), and you'll notice that while it runs, you cannot scroll the page. If it runs long enough, your browser will ask you if you want to kill the process, because it's making the page unresponsive. The frame is being executed, and the event loop and message queue are stuck until it finishes.

So why this side-effect of the text not updating? Because while you have changed the value of the element in the DOM — you can console.log() its value immediately after changing it and see that it has been changed (which shows why DVK's explanation isn't correct) — the browser is waiting for the stack to deplete (the on handler function to return) and thus the message to finish, so that it can eventually get around to executing the message that has been added by the runtime as a reaction to our mutation operation, and in order to reflect that mutation in the UI.

This is because we are actually waiting for code to finish running. We haven't said "someone fetch this and then call this function with the results, thanks, and now I'm done so imma return, do whatever now," like we usually do with our event-based asynchronous Javascript. We enter a click event handler function, we update a DOM element, we call another function, the other function works for a long time and then returns, we then update the same DOM element, and then we return from the initial function, effectively emptying the stack. And then the browser can get to the next message in the queue, which might very well be a message generated by us by triggering some internal "on-DOM-mutation" type event.

The browser UI cannot (or chooses not to) update the UI until the currently executing frame has completed (the function has returned). Personally, I think this is rather by design than restriction.

Why does the setTimeout thing work then? It does so, because it effectively removes the call to the long-running function from its own frame, scheduling it to be executed later in the window context, so that it itself can return immediately and allow the message queue to process other messages. And the idea is that the UI "on update" message that has been triggered by us in Javascript when changing the text in the DOM is now ahead of the message queued for the long-running function, so that the UI update happens before we block for a long time.

Note that a) The long-running function still blocks everything when it runs, and b) you're not guaranteed that the UI update is actually ahead of it in the message queue. On my June 2018 Chrome browser, a value of 0 does not "fix" the problem the fiddle demonstrates — 10 does. I'm actually a bit stifled by this, because it seems logical to me that the UI update message should be queued up before it, since its trigger is executed before scheduling the long-running function to be run "later". But perhaps there're some optimisations in the V8 engine that may interfere, or maybe my understanding is just lacking.

Okay, so what's the problem with using setTimeout, and what's a better solution for this particular case?

First off, the problem with using setTimeout on any event handler like this, to try to alleviate another problem, is prone to mess with other code. Here's a real-life example from my work:

A colleague, in a mis-informed understanding on the event loop, tried to "thread" Javascript by having some template rendering code use setTimeout 0 for its rendering. He's no longer here to ask, but I can presume that perhaps he inserted timers to gauge the rendering speed (which would be the return immediacy of functions) and found that using this approach would make for blisteringly fast responses from that function.

First problem is obvious; you cannot thread javascript, so you win nothing here while you add obfuscation. Secondly, you have now effectively detached the rendering of a template from the stack of possible event listeners that might expect that very template to have been rendered, while it may very well not have been. The actual behaviour of that function was now non-deterministic, as was — unknowingly so — any function that would run it, or depend on it. You can make educated guesses, but you cannot properly code for its behaviour.

The "fix" when writing a new event handler that depended on its logic was to also use setTimeout 0. But, that's not a fix, it is hard to understand, and it is no fun to debug errors that are caused by code like this. Sometimes there's no problem ever, other times it concistently fails, and then again, sometimes it works and breaks sporadically, depending on the current performance of the platform and whatever else happens to going on at the time. This is why I personally would advise against using this hack (it is a hack, and we should all know that it is), unless you really know what you're doing and what the consequences are.

But what can we do instead? Well, as the referenced MDN article suggests, either split the work into multiple messages (if you can) so that other messages that are queued up may be interleaved with your work and executed while it runs, or use a web worker, which can run in tandem with your page and return results when done with its calculations.

Oh, and if you're thinking, "Well, couldn't I just put a callback in the long-running function to make it asynchronous?," then no. The callback doesn't make it asynchronous, it'll still have to run the long-running code before explicitly calling your callback.

@Jani Devang 2018-01-22 07:27:14

Javascript is single threaded application so that don't allow to run function concurrently so to achieve this event loops are use. So exactly what setTimeout(fn, 0) do that its pussed into task quest which is executed when your call stack is empty. I know this explanation is pretty boring, so i recommend you to go through this video this will help you how things work under the hood in browser. Check out this video:- https://www.youtube.com/watch?time_continue=392&v=8aGhZQkoFbQ

@Arley 2013-02-25 21:27:03

Most browsers have a process called main thread, that is responsible for execute some JavaScript tasks, UI updates e.g.: painting, redraw or reflow, etc.

Some JavaScript execution and UI update tasks are queued to the browser message queue, then are dispatched to the browser main thread to be executed.

When UI updates are generated while the main thread is busy, the tasks are added into the message queue.

setTimeout(fn, 0); add this fn to the end of the queue to be executed. It schedules a task to be added on the message queue after a given amount of time.

@bhavya_w 2014-12-18 07:07:47

"Every JavaScript execution and UI update tasks are added to the browser event queue system, then those tasks are dispatched to the browser main UI Thread to be performed."....source please?

@Arley 2014-12-23 23:41:26

High Performance JavaScript (Nicholas Zakas, Stoyan Stefanov, Ross Harmes, Julien Lecomte, and Matt Sweeney)

@Green 2018-05-29 12:35:47

Downvote for this add this fn to the end of the queue. Most important is where exactly setTimeout adds this func, end of this loop cycle or very start of next loop cycle.

@DVK 2011-01-01 17:53:17

Preface:

IMPORTANT NOTE: While it's most upvoted and accepted, the accepted answer by @staticsan actually is NOT CORRECT! - see David Mulder's comment for explanation why.

Some of the other answers are correct but don't actually illustrate what the problem being solved is, so I created this answer to present that detailed illustration.

As such, I am posting a detailed walk-through of what the browser does and how using setTimeout() helps. It looks longish but is actually very simple and straightforward - I just made it very detailed.

UPDATE: I have made a JSFiddle to live-demonstrate the explanation below: http://jsfiddle.net/C2YBE/31/ . Many thanks to @ThangChung for helping to kickstart it.

UPDATE2: Just in case JSFiddle web site dies, or deletes the code, I added the code to this answer at the very end.


DETAILS:

Imagine a web app with a "do something" button and a result div.

The onClick handler for "do something" button calls a function "LongCalc()", which does 2 things:

  1. Makes a very long calculation (say takes 3 min)

  2. Prints the results of calculation into the result div.

Now, your users start testing this, click "do something" button, and the page sits there doing seemingly nothing for 3 minutes, they get restless, click the button again, wait 1 min, nothing happens, click button again...

The problem is obvious - you want a "Status" DIV, which shows what's going on. Let's see how that works.


So you add a "Status" DIV (initially empty), and modify the onclick handler (function LongCalc()) to do 4 things:

  1. Populate the status "Calculating... may take ~3 minutes" into status DIV

  2. Makes a very long calculation (say takes 3 min)

  3. Prints the results of calculation into the result div.

  4. Populate the status "Calculation done" into status DIV

And, you happily give the app to users to re-test.

They come back to you looking very angry. And explain that when they clicked the button, the Status DIV never got updated with "Calculating..." status!!!


You scratch your head, ask around on StackOverflow (or read docs or google), and realize the problem:

The browser places all its "TODO" tasks (both UI tasks and JavaScript commands) resulting from events into a single queue. And unfortunately, re-drawing the "Status" DIV with the new "Calculating..." value is a separate TODO which goes to the end of the queue!

Here's a breakdown of the events during your user's test, contents of the queue after each event:

  • Queue: [Empty]
  • Event: Click the button. Queue after event: [Execute OnClick handler(lines 1-4)]
  • Event: Execute first line in OnClick handler (e.g. change Status DIV value). Queue after event: [Execute OnClick handler(lines 2-4), re-draw Status DIV with new "Calculating" value]. Please note that while the DOM changes happen instantaneously, to re-draw the corresponding DOM element you need a new event, triggered by the DOM change, that went at the end of the queue.
  • PROBLEM!!! PROBLEM!!! Details explained below.
  • Event: Execute second line in handler (calculation). Queue after: [Execute OnClick handler(lines 3-4), re-draw Status DIV with "Calculating" value].
  • Event: Execute 3rd line in handler (populate result DIV). Queue after: [Execute OnClick handler(line 4), re-draw Status DIV with "Calculating" value, re-draw result DIV with result].
  • Event: Execute 4th line in handler (populate status DIV with "DONE"). Queue: [Execute OnClick handler, re-draw Status DIV with "Calculating" value, re-draw result DIV with result; re-draw Status DIV with "DONE" value].
  • Event: execute implied return from onclick handler sub. We take the "Execute OnClick handler" off the queue and start executing next item on the queue.
  • NOTE: Since we already finished the calculation, 3 minutes already passed for the user. The re-draw event didn't happen yet!!!
  • Event: re-draw Status DIV with "Calculating" value. We do the re-draw and take that off the queue.
  • Event: re-draw Result DIV with result value. We do the re-draw and take that off the queue.
  • Event: re-draw Status DIV with "Done" value. We do the re-draw and take that off the queue. Sharp-eyed viewers might even notice "Status DIV with "Calculating" value flashing for fraction of a microsecond - AFTER THE CALCULATION FINISHED

So, the underlying problem is that the re-draw event for "Status" DIV is placed on the queue at the end, AFTER the "execute line 2" event which takes 3 minutes, so the actual re-draw doesn't happen until AFTER the calculation is done.


To the rescue comes the setTimeout(). How does it help? Because by calling long-executing code via setTimeout, you actually create 2 events: setTimeout execution itself, and (due to 0 timeout), separate queue entry for the code being executed.

So, to fix your problem, you modify your onClick handler to be TWO statements (in a new function or just a block within onClick):

  1. Populate the status "Calculating... may take ~3 minutes" into status DIV

  2. Execute setTimeout() with 0 timeout and a call to LongCalc() function.

    LongCalc() function is almost the same as last time but obviously doesn't have "Calculating..." status DIV update as first step; and instead starts the calculation right away.

So, what does the event sequence and the queue look like now?

  • Queue: [Empty]
  • Event: Click the button. Queue after event: [Execute OnClick handler(status update, setTimeout() call)]
  • Event: Execute first line in OnClick handler (e.g. change Status DIV value). Queue after event: [Execute OnClick handler(which is a setTimeout call), re-draw Status DIV with new "Calculating" value].
  • Event: Execute second line in handler (setTimeout call). Queue after: [re-draw Status DIV with "Calculating" value]. The queue has nothing new in it for 0 more seconds.
  • Event: Alarm from the timeout goes off, 0 seconds later. Queue after: [re-draw Status DIV with "Calculating" value, execute LongCalc (lines 1-3)].
  • Event: re-draw Status DIV with "Calculating" value. Queue after: [execute LongCalc (lines 1-3)]. Please note that this re-draw event might actually happen BEFORE the alarm goes off, which works just as well.
  • ...

Hooray! The Status DIV just got updated to "Calculating..." before the calculation started!!!



Below is the sample code from the JSFiddle illustrating these examples: http://jsfiddle.net/C2YBE/31/ :

HTML code:

<table border=1>
    <tr><td><button id='do'>Do long calc - bad status!</button></td>
        <td><div id='status'>Not Calculating yet.</div></td>
    </tr>
    <tr><td><button id='do_ok'>Do long calc - good status!</button></td>
        <td><div id='status_ok'>Not Calculating yet.</div></td>
    </tr>
</table>

JavaScript code: (Executed on onDomReady and may require jQuery 1.9)

function long_running(status_div) {

    var result = 0;
    // Use 1000/700/300 limits in Chrome, 
    //    300/100/100 in IE8, 
    //    1000/500/200 in FireFox
    // I have no idea why identical runtimes fail on diff browsers.
    for (var i = 0; i < 1000; i++) {
        for (var j = 0; j < 700; j++) {
            for (var k = 0; k < 300; k++) {
                result = result + i + j + k;
            }
        }
    }
    $(status_div).text('calculation done');
}

// Assign events to buttons
$('#do').on('click', function () {
    $('#status').text('calculating....');
    long_running('#status');
});

$('#do_ok').on('click', function () {
    $('#status_ok').text('calculating....');
    // This works on IE8. Works in Chrome
    // Does NOT work in FireFox 25 with timeout =0 or =1
    // DOES work in FF if you change timeout from 0 to 500
    window.setTimeout(function (){ long_running('#status_ok') }, 0);
});

@kumikoda 2013-05-10 05:19:44

great answer DVK! Here is a gist that illustrates your example gist.github.com/kumikoda/5552511#file-timeout-html

@thangchung 2013-12-11 10:09:26

Really cool answer, DVK. Just to make easy to imagine, I have put that code to jsfiddle jsfiddle.net/thangchung/LVAaV

@DVK 2013-12-23 16:50:15

@ThangChung - I tried to make a better version (2 buttons, one for each case) in JSFiddle. It works as a demo on Chrome and IE but not on FF for some reason - see jsfiddle.net/C2YBE/31. I asked why FF doesn't work here: stackoverflow.com/questions/20747591/…

@Shog9 2013-12-29 07:15:37

FYI: this answer was merged here from stackoverflow.com/questions/4574940/…

@Alexander Ruliov 2014-12-11 12:50:44

Even better to write long_running in coroutine-style and do setTimeout sometimes inside of calculations. Because when you do the calculations, all page hangs.

@bhavya_w 2014-12-18 06:50:58

@DVK "The browser places all its "TODO" tasks (both UI tasks and JavaScript commands) resulting from events into a single queue". Sir can you please provide the source for this? Imho arent browsers supposed to have different UI ( rendering engine ) and JS threads....no offense intended....just want to learn..

@Seba Kerckhof 2015-02-20 12:03:37

@bhavya_w No, everything happens on one thread. This is the reason a long js calculation can block the UI

@d512 2015-03-10 04:30:19

Good answer but the demo doesn't work terribly well on Chrome anymore. I tried it on Chrome 41.0.2272.76 for OS X and Windows. I'd say maybe half the time "calculating..." actually appears.

@DVK 2015-03-10 20:34:24

@user1334007 - try tweaking the timings.

@d512 2015-03-10 22:01:03

I did and that works, but isn't the whole point of this thread that you shouldn't have to rely on timing to get this to work? Shouldn't it work with an argument of 0?

@DVK 2015-03-11 15:21:14

@d512 2015-03-11 17:02:23

@DVK, your post at stackoverflow.com/questions/20747591/… seems to echo my sentiments. You seem to be saying that it never works in FF with timeout 0 (which I agree with) and I'm saying it only works sometimes in Chrome with timeout 0. Am I missing something?

@DRAB 2015-07-07 18:17:51

This answer directly coincides with everything I've learned about browser event loops. But I too am experiencing problems in FF -- even the Fiddle does not work as advertised. Merely changing the timing in the setTimeout is not an acceptable answer, as that will entirely depend on the CPU of the machine running the code. This must have something to do with the way Mozilla has decided to implement their task queue, but I unfortunately cannot find more information about it. Has anyone else come up with a better, cross-browser solution?

@Green 2015-10-22 12:00:51

Stop, stop! Totally unclear. What is going on when you explain the first section (contents of the queue after each event)? When all those events, that are placed in the queue, are ACTUALLY executed? For now I see that you only populate the queue with them. But when do they begin execution? How is it possible "NOTE: Since we already finished the calculation, 3 minutes already passed for the user"? When did calculation happen? You only placed events into the queue, no any real execution started from your explanation.

@daremkd 2016-01-18 01:48:13

You say "Event: Execute first line in OnClick handler (e.g. change Status DIV value)." and provide the queue after it. Isn't the queue after this supposed to be REMOVED from the queue, thus the queue length to be 1, instead of 2?

@Razort4x 2016-02-10 08:14:14

@DVK: That was a really good explanation, but just the one thing that I didn't got. And unfortunately, re-drawing the "Status" DIV with the new "Calculating..." value is a separate TODO which goes to the end of the queue! Why end of the queue??? Why not in start or rather where it's written? Any specific reason for putting it at the end of the queue.?

@Neil 2016-06-17 11:06:55

This answer is complete and utter nonsense. It doesn't actually answer the OP's question, is needlessly complex, convoluted and worst of all wrong! JavaScript timers - NEVER - read NEVER EVER fire after 0ms - and especially just because you have passed in 0 to setTimeout(). You also should be able to write your explanation without using jQuery, especially as the value of setTimeout(fn, 0) is nothing whatsoever to do with the DOM.

@Tomas Petricek 2016-07-29 21:44:50

TOO MUCH BOLD FACE

@Alex 2016-12-12 06:41:58

@Neil I don't get where you are coming from. Where is he even saying that the timer fires after 0 ms?

@Neil 2016-12-12 11:37:51

@Alex - well there is so much nonsense here it hard to see but: 'Alarm from the timeout goes off, 0 seconds later'.

@Neil 2016-12-12 11:57:18

The correct answer to the OPs question is: Passing '0' to setTimeout" is syntactic sugar for "Please call me back ASAP", where ASAP is the last message in the current event queue. This allows the current call stack to unwind and execute the next message in the queue. You could equally write setTimeout(fn,1) or 2,3,4. The reason it is useful is it allows the call stack to unwind and allow the JS engine to process other events. See: developer.mozilla.org/en/docs/Web/JavaScript/…

@CapturedTree 2017-02-10 06:08:35

This question makes a lot more sense after watching this: 2014.jsconf.eu/speakers/… Skip to 10:24 if you want to get to the point otherwise just skip and watch the video from the start since the beginning is fairly basic

@AGamePlayer 2018-09-16 11:08:08

may I know what is the difference between window.setTimeout and setTimout?

@iappwebdev 2019-01-29 21:20:22

@AGamePlayer It's the same function. As setTimeout is a variable of the object window, you can call it without window prefix. Same thing like e.g. console.log, console is a window object and can be used without window prefix.

@erhan355 2019-02-20 21:22:56

As far as I understand re-draw event $('#status').text('calculating....'); is put on queue.Before browser finds chance to execute it , long_running function is executed.When for loop inside that function is completed another re-draw event is put on the queue which is $(status_div).text('calculation done'). So we leave with two re-drawing events which haven't taken from the queue yet.At that point $('#status').text('calculating....') re-draw is done and right after that $(status_div).text('calculation done'); re-draw is done.

@erhan355 2019-02-20 21:28:12

If we use setTimeout() with a timeout of 0, we actually give the browser a chance to finish doing some non-JavaScript which stays in the queue.In our case it is the re-draw event $('#status').text('calculating....') .By doing so,before long_running is executed browser changes status div text to calculating. Do I miss something ?

@Pointy 2011-01-01 17:38:04

One reason to do that is to defer the execution of code to a separate, subsequent event loop. When responding to a browser event of some kind (mouse click, for example), sometimes it's necessary to perform operations only after the current event is processed. The setTimeout() facility is the simplest way to do it.

edit now that it's 2015 I should note that there's also requestAnimationFrame(), which isn't exactly the same but it's sufficiently close to setTimeout(fn, 0) that it's worth mentioning.

@Zaibot 2011-01-03 14:54:44

This is precisely one of the places where I've seen it being used. =)

@Shog9 2013-12-29 07:15:52

FYI: this answer was merged here from stackoverflow.com/questions/4574940/…

@Green 2015-10-22 09:08:51

is to defer the execution of code to a separate, subsequent event loop: how do you figure out a subsequent event loop? How do you figure out what is a current event loop? How do you know in what event loop turn you are now?

@Pointy 2015-10-22 12:40:02

@Green well, you don't, really; there's really no direct visibility into what the JavaScript runtime is up to.

@David 2016-01-21 16:10:16

requestAnimationFrame solved the problem I was having with IE and Firefox not updating UI sometimes

@Stephan G 2015-09-02 15:39:58

setTimout on 0 is also very useful in the pattern of setting up a deferred promise, which you want to return right away:

myObject.prototype.myMethodDeferred = function() {
    var deferredObject = $.Deferred();
    var that = this;  // Because setTimeout won't work right with this
    setTimeout(function() { 
        return myMethodActualWork.call(that, deferredObject);
    }, 0);
    return deferredObject.promise();
}

@Salvador Dali 2014-05-19 21:34:47

This is an old questions with old answers. I wanted to add a new look at this problem and to answer why is this happens and not why is this useful.

So you have two functions:

var f1 = function () {    
   setTimeout(function(){
      console.log("f1", "First function call...");
   }, 0);
};

var f2 = function () {
    console.log("f2", "Second call...");
};

and then call them in the following order f1(); f2(); just to see that the second one executed first.

And here is why: it is not possible to have setTimeout with a time delay of 0 milliseconds. The Minimum value is determined by the browser and it is not 0 milliseconds. Historically browsers sets this minimum to 10 milliseconds, but the HTML5 specs and modern browsers have it set at 4 milliseconds.

If nesting level is greater than 5, and timeout is less than 4, then increase timeout to 4.

Also from mozilla:

To implement a 0 ms timeout in a modern browser, you can use window.postMessage() as described here.

P.S. information is taken after reading the following article.

@Salvador Dali 2014-10-09 00:21:17

@user2407309 Are you kidding? you mean that the HTML5 specification is wrong and you are correct? Read the sources before you downvote and make strong claims. My answer is based on HTML specification, and historical record. Instead of doing the answer which explains completely the same stuff again and again, I added something new, something that was not shown in previous answers. I am not telling that this is the only reason, I am just showing something new.

@Vladimir Kornea 2014-10-09 00:28:47

This is incorrect: "And here is why: it is not possible to have setTimeout with a time delay of 0 milliseconds." That is not why. The 4ms delay is irrelevant to why setTimeout(fn,0) is useful.

@Salvador Dali 2014-10-09 00:32:01

@user2407309 it can be easily modified to "to add to the reasons stated by others, it is not possible ....". So it is ridiculous to downvote just because of this especially if you own answer is not telling anything new. Just a small edit would be suffice.

@hashchange 2015-07-23 13:27:03

Salvador Dali: If you ignore the emotional aspects of the micro flame war here, you'd probably have to admit that @VladimirKornea is right. It is true that browsers map a 0ms delay to 4ms, but even if they didn't, the results would still be the same. The driving mechanism here is that code is pushed onto the queue, rather than the call stack. Have a look at this excellent JSConf presentation, it may help to clarify the issue: youtube.com/watch?v=8aGhZQkoFbQ

@ShadowRanger 2019-09-27 18:44:40

I'm confused as to why you think your quote on a qualified minimum of 4 ms is a global minimum of 4 ms. As your quote from the HTML5 spec shows, the minimum is 4 ms only when you've nested calls to setTimeout/setInterval more than five levels deep; if you haven't, the minimum is 0 ms (what with lacking time machines). Mozilla's docs expand that to cover repeated, not just nested cases (so setInterval with interval of 0 will reschedule immediately a few times, then delay longer after that), but simple uses of setTimeout with minimal nesting are allowed to immediately queue.

@ChrisN 2013-03-13 23:29:55

The answers about execution loops and rendering the DOM before some other code completes are correct. Zero second timeouts in JavaScript help make the code pseudo-multithreaded, even though it is not.

I want to add that the BEST value for a cross browser / cross platform zero-second timeout in JavaScript is actually about 20 milliseconds instead of 0 (zero), because many mobile browsers can't register timeouts smaller than 20 milliseconds due to clock limitations on AMD chips.

Also, long-running processes that do not involve DOM manipulation should be sent to Web Workers now, as they provide true multithreaded execution of JavaScript.

@John Zabroski 2013-05-19 14:58:40

I am a little skeptical about your answer, but upvoted it because it forced me to do some additional research on browser standards. When researching standards, I go to where I always go, MDN: developer.mozilla.org/en-US/docs/Web/API/window.setTimeout HTML5 spec says 4ms. It doesn't say anything about clock limitations on mobile chips. Having a hard time googling for a source of info to back up your statements. Did find out Dart Language by Google removed setTimeout altogether in favor of a Timer object.

@Piotr Dobrogost 2013-05-30 20:49:53

(...) because many mobile browsers can't register timeouts smaller than 20 milliseconds due to clock limitations (...) Every platform has timing limitations due to its clock and no platform is capable of executing the next thing exactly 0ms after the current one. Timeout of 0ms asks for execution of a function as soon as possible and timing limitations of specific platform does not change the meaning of this in any way.

@fabspro 2012-12-14 13:09:00

Some other cases where setTimeout is useful:

You want to break a long-running loop or calculation into smaller components so that the browser doesn't appear to 'freeze' or say "Script on page is busy".

You want to disable a form submit button when clicked, but if you disable the button in the onClick handler the form will not be submitted. setTimeout with a time of zero does the trick, allowing the event to end, the form to begin submitting, then your button can be disabled.

@Kris 2013-01-06 09:36:10

Disabling would be better done in the onsubmit event; it would be faster and is guaranteed to be called before the form is technically submitted since you can stop the submission.

@fabspro 2014-02-27 08:58:07

Very true. I suppose onclick disabling is easier for prototyping because you can simply type onclick="this.disabled=true" in the button whereas disabling on submit requires slightly more work.

@Jason Suárez 2012-06-21 01:14:43

The other thing this does is push the function invocation to the bottom of the stack, preventing a stack overflow if you are recursively calling a function. This has the effect of a while loop but lets the JavaScript engine fire other asynchronous timers.

@Green 2018-05-29 12:40:41

Downvote for this push the function invocation to the bottom of the stack. What stack are you talking about is obscure. Most important is where exactly setTimeout adds this func, end of this loop cycle or very start of next loop cycle.

@user113716 2011-01-01 17:39:29

Since it is being passed a duration of 0, I suppose it is in order to remove the code passed to the setTimeout from the flow of execution. So if it's a function that could take a while, it won't prevent the subsequent code from executing.

@Shog9 2013-12-29 07:16:08

FYI: this answer was merged here from stackoverflow.com/questions/4574940/…

@Andy 2010-12-06 21:38:30

Take a look at John Resig's article about How JavaScript Timers Work. When you set a timeout, it actually queues the asynchronous code until the engine executes the current call stack.

@Jeremy 2009-04-22 21:53:43

By calling setTimeout you give the page time to react to the whatever the user is doing. This is particularly helpful for functions run during page load.

@Jose Basilio 2009-04-22 21:52:10

setTimeout() buys you some time until the DOM elements are loaded, even if is set to 0.

Check this out: setTimeout

Related Questions

Sponsored Content

26 Answered Questions

[SOLVED] How can I pass a parameter to a setTimeout() callback?

12 Answered Questions

[SOLVED] Why don't self-closing script elements work?

6 Answered Questions

[SOLVED] Why does Google prepend while(1); to their JSON responses?

9 Answered Questions

[SOLVED] Why does ++[[]][+[]]+[+[]] return the string "10"?

  • 2011-08-26 08:46:14
  • JohnJohnGa
  • 198087 View
  • 1616 Score
  • 9 Answer
  • Tags:   javascript syntax

9 Answered Questions

[SOLVED] What is JSONP, and why was it created?

27 Answered Questions

[SOLVED] Why is using "for...in" with array iteration a bad idea?

16 Answered Questions

[SOLVED] Change the selected value of a drop-down list with jQuery

17 Answered Questions

[SOLVED] setTimeout or setInterval?

Sponsored Content