多个setTimeout顺序执行结果的困惑记录

看一段代码:

for(var i=1;i<=5;i++){
    (function(){
    var j=i;
    setTimeout(function timer(){
    console.log(j);
    },j*1000);
    })();
   
 }
for(var i=1;i<=5;i++){
    (function(j){
    setTimeout(function timer(){
    console.log(j);
    },j*1000);
    })(i);
   
}
for(var i=1;i<=5;i++){
    let j=i;
    setTimeout(function timer(){
    console.log(j);
    },j*1000);
   
}
for(let i=1;i<=5;i++){
    setTimeout(function timer(){
    console.log(i);
    },i*1000);
   
}

这段代码执行后的结果是什么?

要弄清楚这个问题,先要明白js的事件循环机制。首先参考HTML规范中的一段话:

为了协调事件(event),用户交互(user interaction),脚本(script),渲染(rendering),网络(networking)等,用户代理(user agent)必须使用事件循环(event loops)。有两类事件循环:一种针对浏览上下文(browsing context),还有一种针对worker(web worker)

事件循环的描述如下:

一个事件循环有一个或者多个任务队列(task queues)。任务队列是task的有序列表,这些task是以下工作的对应算法:Events,Parsing,Callbacks,Using a resource(使用资源),Reacting to DOM manipulation(响应DOM)。

每一个任务都来自一个特定的任务源(task source)。所有来自一个特定任务源并且属于特定事件循环的任务,通常必须被加入到同一个任务队列中,但是来自不同任务源的任务可能会放在不同的任务队列中

举个例子,用户代理有一个处理鼠标和键盘事件的任务队列。用户代理可以给这个队列比其他队列多3/4的执行时间,以确保交互的响应而不让其他任务队列饿死(starving),并且不会乱序处理任何一个任务队列的事件。

每个事件循环都有一个进入microtask(微任务)检查点(performing a microtask checkpoint)的flag标志,这个标志初始为false。它被用来组织反复调用‘进入microtask检查点’的算法。

我们可以看出,任务队列在事件循环中的作用非常重要,那么,我们以将任务队列的执行机制稍作介绍:

待任务可以分为同步任务和异步任务:

同步任务:即立即执行的任务,同步任务一般会直接进入到主线程中执行;

异步任务,即异步执行的任务,例如setTimeout 定时函数,网络请求等都属于异步任务,异步任务会通过任务队列进行管理。

同步和异步任务分别进入不同的执行环境,同步的进入主线程,即主执行栈,异步的进入 任务队列 。主线程内的任务执行完毕为空,会去 Event Queue 读取对应的任务,推入主线程执行。 上述过程的不断重复就是我们说的 Event Loop (事件循环)。

基于以上的机制,我们来分析上面的代码:

代码中是五个异步任务,没有同步任务,因此都进入异步队列,再以先进入先出的顺序执行,我猜测运行结果是顺序输出4个“1 2 3 4 5”串:即

1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 

但是,结果不是这样!而是:

1 1 1 1 2 2 2 2 3 3 3 3 4 4 4 4 5 5 5 5

即先输出4个1,再输出4个2,以此类推;

Why?!!

关于这个问题,我暂时没有想清楚,先记录下来。

引用文章:https://segmentfault.com/a/1190000010622146https://www.cnblogs.com/yugege/p/9598265.html

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值