美文网首页
由SetTimeout引发的

由SetTimeout引发的

作者: 婆娘漂亮生活安逸 | 来源:发表于2019-04-26 16:06 被阅读0次

写在前面的:
才疏学浅,如有不足,多多指出!

之前在关于移动端的长按事件文章中曾经提过 setTimeout,搜索该函数的时候有一道题目让我泛起了很大的疑惑,似乎自己对这方面知识一直不太懂。

console.log("global");

// S_111
setTimeout(function() {
  console.log("timeout1");
  // P_111
  new Promise(function(resolve) {
    console.log("timeout1_promise");
    resolve();
  }).then(function() {
    console.log("timeout1_then");
  });
}, 2000);


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

// P_222
new Promise(function(resolve) {
  console.log("promise1");
  resolve();
}).then(function() {
  console.log("then1");
});

// S_333
setTimeout(function() {
  console.log("timeout2");
  // P_333
  new Promise(function(resolve) {
    console.log("timeout2_promise");
    resolve();
  }).then(function() {
    console.log("timeout2_then");
  });
}, 1000);

// P_444
new Promise(function(resolve) {
  console.log("promise2");
  resolve();
}).then(function() {
  console.log("then2");
});

👇
👇
👇
想要知道答案,可以直接拖到文章最后查看。


如果想要知道上述代码运行的结果,则需要理解以下几个知识点:

1. JS单线程、异步、同步概念

  • JS单线程:只有一个主线程,串行执行一个个任务,后一个任务必须等待前一个任务的执行完成。
  • 异步:由于类似ajax网络请求setTimeout时间延迟DOM事件的用户交互等,需要一些时间的等待,却不需要CPU处理,因此异步执行就是跳过了CPU等待,先去执行主线程中后续任务,等异步模块处理完后在执行相应任务。
  • 同步:同步执行是主线程按照顺序,串行执行任务。

由此产生了任务队列事件循环,来协调主线程与异步模块之间的工作。

2.事件循环机制

  • 执行顺序
    step1:主线程读取JS代码,此时为同步环境,形成相应的堆和执行栈;
    step2: 主线程遇到异步任务,指给对应的异步进程进行处理(WEB API);
    step3: 异步进程处理完毕(Ajax返回、DOM事件、Timer到等),将相应的异步任务推入任务队列;
    step4: 主线程执行完毕,查询任务队列,如果存在任务,则取出一个任务推入主线程处理(先进先出);
    step5: 重复执行step2、3、4;称为事件循环。

  • 执行大意:
     同步环境执行(step1) -> 事件循环1(step4) -> 事件循环2(step4的重复)…

  • 异步进程:
        a、类似onclick等,由浏览器内核的DOM binding模块处理,事件触发时,回调函数添加到任务队列中;
        b、setTimeout等,由浏览器内核的Timer模块处理,时间到达时,回调函数添加到任务队列中;
        c、Ajax,由浏览器内核的Network模块处理,网络请求返回后,添加到任务队列中。

3.任务队列

  • 类型:
    宏观任务队列(macrotask queue):如setTimeout、setInterval
    微观任务队列(microtask queue):如ES6 的Promise.then()
  • 顺序
    在某一次事件循环中,先执行微任务,按串行执行完所有的微任务以后;再去执行宏任务。

4.分析


1)首行直接输出global;
2)遇到第一个 setTimeout,简称 s_111,是宏任务,新建宏任务队列并将其插入队列后,设定为 2 秒后执行。
3)for 循环,遇到 s_222,插入刚才的宏任务队列,输出 i;循环结束后,此时应该在宏任务队列中插入了5个任务,分别延时1-5秒执行;并且直接输出 1,2,3,4,5
4)p_222,Promise 构造函数在实例化时直接执行,因此输出promise1,发现P_222 的 then为微任务,新建微任务队列,将其添加进入;
5) s_333:加入宏任务队列中,1秒后执行。
6)p_444: 同理,直接输出promise2,将P_444 的 then加入刚才的微任务队列;
7)此时,同步环境执行完了可以直接输出的代码,接着执行微任务,也就是P_222 的 thenP_444 的 then,此时输出then1then2


第二轮事件循环开始,执行setTimeout类型队列:
按照时间顺序,其次可以知道该队列顺序应该为:
s_222(for1) -> s_333 -> s_111 -> s_222(for2) -> s_222(for3) -> s_222(for4) -> s_222(for5)
时间越短的任务越前,时间相同时,先进队列的任务越前。
8)s_222(for1) :此时 i 已经变成6,所以输出6
9) s_333:先输出timeout2, timeout2_promise,此时出现了微任务p_333的then,因此会先执行完该任务的所有任务,继续输出timeout2_then
10) s_111:同上分析,输出timeout1, timeout1_promise, timeout1_then
11)接着继续执行刚才for循环中的setTimeout,每隔一秒输出6
12)第二轮循环结束,全部代码执行完毕。


👇
👇
👇
最终结果展示为


相关文章

  • 由SetTimeout引发的

    写在前面的:才疏学浅,如有不足,多多指出! 之前在关于移动端的长按事件文章中曾经提过 setTimeout,搜索该...

  • 由setTimeout引发的对js的异步操作的思考

    今天在看表严肃老师的视频的时候,讲到了setTimeout的操作,由此引发了对js的异步操作的思考。javascr...

  • 2019-01-07

    setTimeout的第一个参数为什么要写函数? 如果setTimeout第一个参数使用字符串而非函数的话,会引发...

  • setTimeout和for循环引发的常识错误

    标签(空格分隔): javascript 最近想要去实现一个定时函数,定时的去改变一个元素的opacity,从而实...

  • setTimeout引发的刨根问底

    setTimeout(定时器)是JavaScript中一个比较重要且常用的方法,该方法用于在指定的毫秒数后调用函数...

  • 由吃引发的

    一 食,色,性也。人活在世,离不开吃喝拉撒。民以食为天,吃是果腹,生存之必须。吃也可以是舌尖的味道,味蕾的诱惑。 ...

  • 由“缺钙”引发的……

    几个月前社区医院在没有任何问诊的情况下就让我给孩子补钙,而且给了我一个私人电话让我私下联系购买。因为当时近期大医院...

  • 由健忘引发的~

    世界上没有记忆的人,除了失忆症,就很少因素了,但是我不是在这里说失忆症。而是想说人的健忘到底是怎么回事? 人的大脑...

  • 由脸引发的

    这个看颜值的世界,除了脸,还能看什么? 现在,我身边有很多不折不扣的外貌协会,我并不排除在外。 我们臭味相投,爱看...

  • 由国足引发的……

    土豪为智障儿子请了个哈佛教授, 事实证明:老师绝不是万能的。 某男足=世界名帅终结者, 里皮大爷,再见,回去歇着吧...

网友评论

      本文标题:由SetTimeout引发的

      本文链接:https://www.haomeiwen.com/subject/dbwygqtx.html