请问为什么会在for循环结束才会执行异步函数?
发布于 10 年前 作者 youqingkui 12088 次浏览 最后一次编辑是 8 年前

请看这段代码:

for(var i=0; i<10; i++){
  var now = new Date();
  while (new Date - now < 1000);
  console.log("here");
  setTimeout(function(){
    console.log(i);
  }, 5000);
}

setTimeout在这应该是异步函数吧!我使用了while来使每个循环延迟1s,按理当执行第一次循环执行了setTimeout,他会在后台静默执行,不会阻塞。但是console.log(i);都是在循环执行完成后才会输出。请问这是什么原因?谢谢!

另外我注意到循环结束后立刻输出了4个console.log(i);那应该是执行循环后setTimeout就已经在后台执行了? 输出如下:here here here here here here here here here here 10 10 10 10 10 10 10 10 10 10

13 回复

在for里面用自调函数就好了

@TamudGu 可否讲详细些,或者给个例子。多谢!:)

@TamudGu 可能我的表达有点错误。我不在乎console.log(i);输出的是什么值。而是奇怪为什么要循环结束后才会将console.log(i);输出?

我知道console.log(i); 输出的值是10,但是奇怪的是为什么要循环结束才会输出?而不是在执行循环的时候输出值?

settimeout是js中很重要一个原生函数,也是实现promise的核心。 javascript代码都是同步执行的,代码都在在一个代码“队列”里面。与此同时javascript还有一个“Event Queue”,事件队列里都是处理一些异步的callback/handler,处理ajax response,点击啊,文件,数据库操作结果。关键是,只有代码队列所有代码都执行完毕了,javascript才会从事件队列里取出一个callback/handler来执行。 在你的例子里面,settimeout就是把callback,放到了这个事件队列里面,直到当前的for loop执行完毕了,js才从事件对列里取出callback,才执行了callback函数,找到执行完毕那个状态下的closure 中i的值,并打印出来,所以即使你设置 settimeout(function(){}, 0); 也是同样的结果。

请问为什么会在for循环结束才会执行异步函数? 如果在for循环中执行异步函数,那就不叫异步了。

@leapon 那是要等for循环结束才会执行异步函数?

@alaaf 那在for循环中执行其他的异步操作也会等循环结束才会执行异步操作吗?另外注意到,循环结束后立刻输出了4个console.log(i);那应该是执行循环后setTimeout就已经在后台执行了?

@youqingkui 是的。当前的函数执行完,才轮到后续排队中的程序。setTimeout 里的回调函数在排队中。

setTimeout 不是异步的,实际上它只是伪异步,造成异步的现状是它用了 插入时间点的机制来实现的,setTimeout的第二个参数指明了执行的时间。所以你写的代码执行结果是没问题的 , 如果楼主不信的话 可以把while写成一个死循环 这样的话 你的setTimeout一辈子都不会执行

for ( var i = 0; i < 5; i++ ) {  
    setTimeout(function() {  
        alert( i );  
    }, i * 100 );  
}

这是JQuery官网上在讲解闭包的时候的一个例子,这里的alert也只会输出5.

参考知乎上的一个解答

@hc2014 楼上说到点上了。我再补充一点,JS是事件驱动的,你调用的setTimeout函数同步地往事件队列里面加任务而已,因为你添加地任务在事件队列里面,所以肯定是当当前任务执行完了才有机会轮到他们pop出来执行。 所以楼上说 while(1){} 这种死循环会block JS引擎,当前任务不结束,其任务完全没机会执行。

所以Node.js的人建议在执行繁重的计算任务的时候分拆代码并使用 process.nextTick

回到顶部