我有一段Javascript代码。
var i, _i, _len, _ref;
_ref = [1, 2, 3];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
i = _ref[_i];
setTimeout((function() {
return console.log(i);
}), 0);
}
它是由一块Coffeescript生成的,这就是为什么它里面有奇怪的名字。执行代码时,输出为3 3 3
。根据执行结果,执行顺序似乎是:
enter for loop
settimeout 1 with a function
settimeout 2 with a function
settimeout 3 with a function
settimeout 1 execute
settimeout 2 execute
settimeout 3 execute
与我的理解有点不同。据我所知,for循环中的setTimeout
以异步方式运行。 setTimeout
语句本身可以即时完成。在几毫秒(在我们的例子中为0)之后,该函数将开始在单独的上下文中执行。所以我的预期执行顺序是:
enter for loop
settimeout 1 with a function
settimeout 2 with a function, settimeout 1 execute
settimeout 3 with a function, settimeout 2 execute
settimeout 3 execute
根据CPU负载和传递给setTimeout
的函数的复杂性,执行顺序可能与我上面描述的不同。但我的观点是,setTimeout可以立即开始执行,并且不需要等待for循环的完成。
希望有人可以帮忙澄清一下。我检查了MDN的setTimeout,但无法获得任何有用的信息。
答案 0 :(得分:1)
有一个事件循环的想法。即使setTimeout设置为0(它实际上不能低于14ms左右),它仍然会被置于事件循环中。所以,你会期望它会瞬间触发,但它可能不会依赖于在上下文之外发生的其他事情,例如,循环运行。
查看此网站,它会让您大吃一惊,以及您需要了解的内容。
答案 1 :(得分:1)
我会尽量简单。 JavaScript是一种单线程语言,这意味着只能在一个实例中进行单个操作。
settimeout 2 with a function, settimeout 1 execute
上面显示的执行顺序是不可能的,这两个语句不会同时执行。 有一个执行队列,它在JavaScript中逐个执行语句 根据上面编写的代码,它的工作顺序如下:
以下是一些可能有用的链接
答案 2 :(得分:1)
对我来说,最好的方法就是改变对JavaScript中任何异步调用的理解,特别是setTimeout
。您可以将其视为向队列中添加一些事件,而不是将setTimeout
视为直接函数调用,只有在其他所有事件完成后才开始运行所有事件。
在您认为这只是添加事件之后,您就会理解它在JavaScript中的自然效果。 JavaScript应用程序是单线程应用程序(大多数时候)。这意味着只要您的同步代码正常工作,它甚至不会开始运行异步请求,因此甚至不会触及队列。
在其他更简单的字词中,setTimeout(..., 0)
正在添加某种&#39; onSyncCodeDone&#39;事件
如何获得预期的执行顺序的唯一方法是使用递归:
var _ref = [1, 2, 3];
function process(index) {
if (index < _ref.length) {
setTimeout((function() {
process(index + 1);
return console.log(index);
}), 0);
}
}
process(0);
答案 3 :(得分:0)
问题是setTimeout将在循环执行后执行。因为那不是同步的。因此setTimeout中的函数将i的值始终为3。
这将是正确的代码......
var i, _i, _len, _ref;
_ref = [1, 2, 3];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
i = _ref[_i];
setTimeout((function(i) {
console.log(i);
})(i), 0);
}
答案 4 :(得分:0)
我在这里简化了循环,你可以在这里看到结果: https://jsfiddle.net/TomKarachristos/L6couu2o/
for ( _i = 0, _len = 3; _i < _len; _i++) {
setTimeout((function() {
makeAParagraph(_i);
}), 0);
}
当执行一段代码时,没有任何东西可以中断执行,因此所有循环都是在没有一个超时运行的情况下执行的。
在每次执行超时时执行该执行,它会将第一个参数(函数)推送到回调队列中。如下图所示。
当循环结束且没有执行JavaScript的代码时,转到回调队列找到第一个函数并执行它。如果这是超时,则首先检查您作为第二个参数放置的时间是否已通过(0总是通过)。
因此第一次超时它在循环结束时运行,当发生这种情况时,i就是3.这里我们有另一种JavaScript命名闭包技术,JavaScript中的函数可以访问函数外部定义的变量。因此,超时内的函数可以访问外部的变量i。但是,当第一次超时被调用时,i为3,如图所示,与第二次和第三次超时相同。