繁体   English   中英

了解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设置为0(它实际上不能低于14ms左右),它仍然会被置于事件循环中。 所以,你会期望它会立即触发,但它可能不会依赖于在上下文之外发生的其他事情,例如,循环运行。

检查这个网站,它会让你大吃一惊,而且你需要了解的内容。

http://latentflip.com/loupe/

我会尽量简单。 JavaScript是一种单线程语言,这意味着只有一次操作才能在一个实例中发生。

settimeout 2 with a function, settimeout 1 execute

上面显示的执行顺序是不可能的,这两个语句不会同时执行。 有一个执行队列在JavaScript中逐个执行语句根据上面编写的代码,它的工作顺序如下:

  1. 你的for循环进入队列并开始运行
  2. SetTimeout函数在指定时间后添加到队列中,在0毫秒后的情况下。
  3. 一旦线程从for循环中释放,SetTimeouts就会从队列中删除并执行。

以下是一些可能有用的链接

http://ejohn.org/blog/how-javascript-timers-work/

http://javascript.info/tutorial/settimeout-setinterval

对我来说,最好的方法是改变对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);

问题是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);
}

我在这里简化了循环,你可以在这里看到结果: https ://jsfiddle.net/TomKarachristos/L6couu2o/

for ( _i = 0, _len = 3; _i < _len; _i++) {
  setTimeout((function() {
    makeAParagraph(_i);
  }), 0);
}

当执行一段代码时,没有任何东西可以中断执行,因此所有循环都在执行而没有一个超时运行。

在该执行中,每次超时发现它都会在回调队列中推送第一个参数(函数)。 如下图所示。

当循环结束并且没有执行JavaScript的代码时,请转到回调队列,找到第一个函数并执行它。 如果这是超时,则首先检查您作为第二个参数放置的时间是否已通过(0始终为通过)。

所以第一次超时它在循环结束时运行,当发生这种情况时,我就是3.这里我们有另一种JavaScript命名闭包技术,JavaScript中的函数可以访问函数外部定义的变量。 因此,超时内的函数可以访问外部的变量i。 但是当第一次超时被调用时,i是3,如图所示,与第二次和第三次超时相同。

在此输入图像描述

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM