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
Execution order of multiple setTimeout() functions with same interval
提问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 #output
is 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 setTimeout
step 8 in section 7.3 is that the execution order issupposed to be guaranteed.
我对setTimeout
7.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 two
to 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 delay
time. So the two setTimeout
generate 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 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.
因为第一个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 Continuum
function 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 test1
and order of execution is still function1
then function2
.
单击test2
,然后单击test1
,执行顺序仍然是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);
}
回答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 中没有定义。