Execution order of multiple setTimeout() functions with same interval

Consider the following Javascript code:

function(){
    setTimeout(function() {
        $("#output").append(" one ");
    }, 1000);
    setTimeout(function() {
        $("#output").append(" two ");
    }, 1000);
}

You can also see this example on jsfiddle.

Can I be sure that the value of #output is always "one two", in that order? Usually, I would handle this problem like this:

function(){
    setTimeout(function() {
        $("#output").append(" one ");
        $("#output").append(" two ");
    }, 1000));
}

But I can not do it that way because I get messages from a server which tells me which function to execute (in this example append "one" or append "two"), which I have to execute with a small delay.

I already tested this code in Internet Explorer 9, Firefox 14, Chrome 20 and Opera 12, and the output was always "one two", but can I be sure that this will always be the case?

Answers:

Answer

The Spec is here.

My interpretation of setTimeout step 8 in section 7.3 is that the execution order is supposed to be guaranteed.

However, I investigated this issue because when the window is minimized and then maximised in Chrome, I was finding that timeouts set in events coming from external sources (like websockets or webworkers) were being executed in the wrong order. I assume this is a browser bug and will hopefully be fixed soon.

Answer

Play around with this in your fiddle

$(document).ready(function() {
    setTimeout(function() {
        $("#output").append(" one ");
    }, 1000);
});
$(document).ready(function() {
    setTimeout(function() {
        $("#output").append(" two ");
    }, 999);
});?

And you will see that both

output: one two
output: two one

are possible. So Speransky is right that you cannot rely on your timeouts executing in the same order always.

Note that I have change one time with 1ms to show that the timeout 1000ms can execute before the 999ms timeout.

EDIT: The below code can delay execution without any chance of two to be printed before one

function(){
    setTimeout(function() {
        $("#output").append(" one ");
       setTimeout(function() {
           $("#output").append(" two ");
       }, 100);
    }, 1000);
}
Answer

Yes, because javascript code is executed in one single thread, all asynchronous events, like click, mousemove, are queued to execute. When you call setTimeout, the engine insert a timer into its queue to execute in future, at least after delay time. So the two setTimeout generate two timers, one after another.

You can have a look at How Javascript Timers Work by John Resig.

Answer

No, you cannot be sure. It is asynchronously.

But in fact it probably will be true, because of realization of the mechanism in browsers.

Answer

Yes, the output will always be "one two".

Because the first setTimeout always runs before the second setTimeout, if they have same delay time, then the callback function of first will always be executed before the callback function of the second.

Answer

Update
I've updated your fiddle with this method. Check it out here

How about this method -- Get a list of things to do from your server --

//Example - append one, append two
var appendList = ['one', 'two']

//then do this
appendList.forEach(function(item, index){
    setTimeout(function(){ 
        $('#output').append(item)
    }, index * 50 + 1000);
});

This way, you decide the sequence.

Answer

If events are synchronous, there is the Continuum function to run functions in sequence:

function keyedSequence(key, fn) {
  fn = fn || this;
  key.push({fn:fn});

  return function() {
    for(var i=0, n, full=1; i<key.length; i++) {
      n = key[i];
      if(n.fn == fn) {
        if(!n.called) n.called = 1, n.args = key.slice.call(arguments);
        if(!full) break
      }
      if(!n.called) full = 0
    }

    if(full) for(i=0; i<key.length; i++)
      n = key[i], key[i] = {fn:n.fn}, n.fn.apply(n, n.args);
  }
}
Function.prototype.seq = keyedSequence;

You provide an empty array as the key. Functions keyed with the same key will be grouped together.

window.onload = function() {
  var key = [];
  document.getElementById("test1").addEventListener('click', function1.seq(key), false);
  document.getElementById("test2").addEventListener('click', function2.seq(key), false);
}

Click test2, then click test1 and order of execution is still function1 then function2.

Another way of calling it is:

window.onload = function() {
  var key = [];
  document.getElementById("test1").addEventListener('click', keyedSequence(key, function1), false);
  document.getElementById("test2").addEventListener('click', keyedSequence(key, function2), false);
}
Answer

It depends on the browser, because setTimout is part of the window object in the browser, not defined in ECMAScript.

Answer

Per spec, the have the same task source, and things that have the same task source should be ordered. So yes.

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.