由SetTimeout引发的

2019-04-26  本文已影响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单线程、异步、同步概念

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

2.事件循环机制

3.任务队列

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)第二轮循环结束,全部代码执行完毕。


👇
👇
👇
最终结果展示为


上一篇 下一篇

猜你喜欢

热点阅读