Javascript 学习篇- EventLoop

186 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 12 天,点击查看活动详情

什么是Event Loop

Event Loop 即事件循环(事件轮询),是指浏览器或者Node 的一种解决JavaScript 单线程运行时不阻塞的一种机制,也就是经常使用的异步。

EventLoop 事件循环

掌握了事件循环有助于我们去理解 js 带的运行机制。

事件分类

  • 同步任务
  • 异步任务
    • 宏任务
    • 微任务

同步

代码按照上下文执行顺序一次执行。

// 同步任务
console.log(1);
console.log(2);
console.log(3);

异步

- 宏任务
- 微任务
  • 同步任务1
  • 异步任务
    • 宏任务3
      • setTimeout
      • setInterval
      • setImmediate (Node独有)
      • requestAnimationFrame (浏览器独有)
      • I/O
      • UI rendering (浏览器独有)
    • 微任务2
      • process.nextTick (Node独有)
      • Promise.then
      • Object.observe
      • MutationObserver

image.png

浏览器对JavaScript代码的执行流程如下

  • 执行代码的同步部分
  • 把微任务队列里的任务全部执行
  • 执行宏任务的第一个任务(执行完有可能产生微任务),如果产生了微任务,将微任务推进微任务队列
  • 全局Script代码执行完毕后,调用栈Stack会清空;
  • 从微队列microtask queue中取出位于队首的回调任务,放入调用栈Stack中执行,执行完后microtask queue长度减1;
  • 继续取出位于队首的任务,放入调用栈Stack中执行,以此类推,直到直到把microtask queue中的所有任务都执行完毕。注意,如果在执行microtask的过程中,又产生了microtask,那么会加入到队列的末尾,也会在这个周期被调用执行;

总结:

  • 微任务队列优先于宏任务队列执行,(宏任务优先级最低)
  • 微任务队列上创建的宏任务会被后添加到当前宏任务队列的尾端,微任务队列中创建的微任务会被添加到微任务队列的尾端。
  • 只要微任务队列中还有任务,宏任务队列就只会等待微任务队列执行完毕后再执行

l

实操一下

const p1 = new Promise((res, rej) => {
  console.log("Promise");
  res(1);
});

// 第一个宏任务
setTimeout(function () {
  console.log(1);
  setTimeout(function () {
    console.log(2);
    p1.then(res => {
      console.log(3);
    });
  }, 0);
  console.log(4);
}, 0);

// 第二个微任务
setTimeout(() => {
  process.nextTick(() => {
    p1.then(res => {
      console.log(5);
      setTimeout(function () {
        console.log(6);
        p1.then(res => {
          console.log(7);
          console.log("2:" + res);
        });
        console.log(8);
      }, 0);
      console.log(9);
    });
  });
});

观察下面代码的执行顺序:

console.log(1);
console.log(3);
Promise.resolve(4).then((res) => {
  console.log(res);
});
setTimeout(() => {
  console.log(2);
}, 0);

我们可以得知,先执行同步任务,在执行异步任务。
异步任务当中有宏任务、微任务,先执行微任务

宏任务和微任务的优先级

console.log(1);
console.log(3);
Promise.resolve(4).then((res) => {
  console.log(res);
});
setTimeout(() => {
  console.log(2);
}, 0);

我们可以得知,先执行同步任务,在执行异步任务。
异步任务当中有宏任务、微任务,先执行微任务

宏任务嵌套

console.log(1);
setTimeout(() => {
  console.log(7);
  setTimeout(() => {
    console.log(3);
  });
  console.log(8);
  Promise.resolve(4).then((res) => {
    console.log(res);
  });
  console.log(9);
}, 0);
setTimeout(() => {
  console.log(10);
  Promise.resolve(5).then((res) => {
    console.log(res);
  });
  console.log(11);
  setTimeout(() => {
    console.log(6);
  });
  console.log(12);
});
console.log(2);


// 1 2 789  4 101112 5  3 6