Javascript 具有相同间隔的多个 setTimeout() 函数的执行顺序

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11771558/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 07:02:02  来源:igfitidea点击:

Execution order of multiple setTimeout() functions with same interval

javascript

提问by Uooo

Consider the following Javascript code:

考虑以下 Javascript 代码:

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

You can also see this example on jsfiddle.

你也可以在jsfiddle上看到这个例子。

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

我能确定 的值#output总是"one two"按这个顺序吗?通常,我会这样处理这个问题:

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.

但是我不能那样做,因为我从服务器获取消息,该消息告诉我要执行哪个函数(在本例中为 append"one"或 append "two"),我必须以很小的延迟执行该函数。

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?

我已经在 Internet Explorer 9、Firefox 14、Chrome 20 和 Opera 12 中测试了此代码,并且输出始终为"one two",但我能确定情况始终如此吗?

采纳答案by kybernetikos

The Spec is here.

规格在这里

My interpretation of setTimeoutstep 8 in section 7.3 is that the execution order issupposed to be guaranteed.

我对setTimeout7.3 节第 8 步的解释应该保证执行顺序。

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.

但是,我调查了这个问题,因为当窗口在 Chrome 中最小化然后最大化时,我发现在来自外部源(如 websockets 或 webworkers)的事件中设置的超时以错误的顺序执行。我认为这是一个浏览器错误,希望很快得到修复。

回答by bart s

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.

是可能的。所以 Speransky 是对的,你不能依赖你的超时总是以相同的顺序执行。

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

请注意,我用 1ms 更改了一次,以表明可以在 999ms 超时之前执行 1000ms 的超时。

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

编辑:下面的代码可以延迟执行而没有任何机会two在之前被打印one

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

回答by xiaowl

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 delaytime. So the two setTimeoutgenerate two timers, one after another.

是的,因为 javascript 代码是在一个线程中执行的,所以所有异步事件,如click, mousemove,都排队等待执行。当您调用 时setTimeout,引擎会在其队列中插入一个计时器,以便将来至少在delay一段时间后执行。所以两者setTimeout产生了两个定时器,一个接一个。

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

您可以查看John Resig 的How Javascript Timers Work

回答by Danil Speransky

No, you cannot be sure. It is asynchronously.

不,你不能确定。它是异步的。

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

但实际上它可能会是真的,因为浏览器中的机制的实现。

回答by xdazz

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

是的,输出将始终为"one two".

Because the first setTimeoutalways 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.

因为第一个setTimeout总是在第二个之前运行setTimeout,如果它们的延迟时间相同,那么第一个的回调函数将始终在第二个的回调函数之前执行。

回答by Jibi Abraham

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.

这样,您就可以决定顺序。

回答by Kernel James

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

如果事件是同步的,则有Continuum按顺序运行函数的函数:

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 test1and order of execution is still function1then function2.

单击test2,然后单击test1,执行顺序仍然是function1then 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);
}

回答by Ini

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

这取决于浏览器,因为 setTimout 是浏览器中 window 对象的一部分,在 ECMAScript 中没有定义。