了解 Javascript 代码执行顺序
Understanding of Javascript code execution order
我有一段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 但没有得到任何有用的信息。
问题是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);
}
有一个事件循环的想法。即使 setTimeout 设置为 0(它实际上不能低于 14 毫秒左右),它仍然被放置在事件循环中。因此,您希望它会立即触发,但它可能不依赖于上下文之外发生的其他情况,例如,循环 运行.
查看此站点,它会让您大吃一惊,并且正是您需要了解的内容。
我会尽量简单。 JavaScript 是一种单线程语言,这意味着在一个实例中只会发生单个操作。
settimeout 2 with a function, settimeout 1 execute
你上面写的执行顺序是不可能的,两条语句不会同时执行。
有一个执行队列,在 JavaScript 中一条一条地执行语句
根据您上面编写的代码,它的工作顺序如下:
- 您的 for 循环进入队列并开始 运行
- SetTimeout 函数在指定时间后添加到队列中,在您的例子中是在 0 毫秒后。
- 一旦线程从 for 循环中解脱出来,SetTimeouts 就会从队列中移除并执行。
这里有一些可能有用的链接
对我来说,最好的解释方法是改变对 JavaScript 中任何异步调用的理解,尤其是 setTimeout
。与其将 setTimeout
视为直接函数调用,不如将其视为向队列中添加一些事件,该队列将仅在其他所有操作完成后才开始 运行 处理所有事件。
当你认为这只是添加事件后,你就会明白它是如何在 JavaScript 中自然工作的。 JavaScript 应用程序是单线程应用程序(大部分时间)。所以这意味着只要您的同步代码在工作,它甚至不会开始 运行 异步请求,所以甚至不会触及队列。
换句话说,更简单地说,setTimeout(..., 0)
正在添加某种 'onSyncCodeDone' 事件。
获得预期执行顺序的唯一方法是使用递归:
var _ref = [1, 2, 3];
function process(index) {
if (index < _ref.length) {
setTimeout((function() {
process(index + 1);
return console.log(index);
}), 0);
}
}
process(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可以访问函数外定义的变量。所以timeout里面的函数可以访问外面的变量i。但是当第一次超时被调用时,i是3,如图所示,第二次和第三次超时也是如此。
我有一段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 但没有得到任何有用的信息。
问题是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);
}
有一个事件循环的想法。即使 setTimeout 设置为 0(它实际上不能低于 14 毫秒左右),它仍然被放置在事件循环中。因此,您希望它会立即触发,但它可能不依赖于上下文之外发生的其他情况,例如,循环 运行.
查看此站点,它会让您大吃一惊,并且正是您需要了解的内容。
我会尽量简单。 JavaScript 是一种单线程语言,这意味着在一个实例中只会发生单个操作。
settimeout 2 with a function, settimeout 1 execute
你上面写的执行顺序是不可能的,两条语句不会同时执行。 有一个执行队列,在 JavaScript 中一条一条地执行语句 根据您上面编写的代码,它的工作顺序如下:
- 您的 for 循环进入队列并开始 运行
- SetTimeout 函数在指定时间后添加到队列中,在您的例子中是在 0 毫秒后。
- 一旦线程从 for 循环中解脱出来,SetTimeouts 就会从队列中移除并执行。
这里有一些可能有用的链接
对我来说,最好的解释方法是改变对 JavaScript 中任何异步调用的理解,尤其是 setTimeout
。与其将 setTimeout
视为直接函数调用,不如将其视为向队列中添加一些事件,该队列将仅在其他所有操作完成后才开始 运行 处理所有事件。
当你认为这只是添加事件后,你就会明白它是如何在 JavaScript 中自然工作的。 JavaScript 应用程序是单线程应用程序(大部分时间)。所以这意味着只要您的同步代码在工作,它甚至不会开始 运行 异步请求,所以甚至不会触及队列。
换句话说,更简单地说,setTimeout(..., 0)
正在添加某种 'onSyncCodeDone' 事件。
获得预期执行顺序的唯一方法是使用递归:
var _ref = [1, 2, 3];
function process(index) {
if (index < _ref.length) {
setTimeout((function() {
process(index + 1);
return console.log(index);
}), 0);
}
}
process(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可以访问函数外定义的变量。所以timeout里面的函数可以访问外面的变量i。但是当第一次超时被调用时,i是3,如图所示,第二次和第三次超时也是如此。