简单谈谈事件循环(Event Loop)

339 阅读3分钟

这是我参与更文挑战的第25天,活动详情查看: 更文挑战

前言

事件循环经常会出现面试官的面试题,因为这个可以考察面试者对执行栈,任务队列,宏任务,微任务等方面的了解程度。我也看了很多文章,但是每次都感觉看的有点囫囵吞枣,或者看完后就忘了,今天借着这次机会,把它复习一遍。

事件循环

首先我们要知道,js是单线程的,就是一个任务执行完,接着下一个任务执行,按照顺序执行。但是如果任务是一个很耗时的任务,那就把线程都堵住了,后面的任务都执行不了。为了防止这种情况:

js把任务分为同步任务异步任务

概括起来:先执行同步任务,再执行异步任务。重复如始。

列举一些同步任务

console.log(1);
console.log(2);
console.log(3);
for(let i = 4; i <= 10; i++) {
  console.log(i)
}
function test () {
 console.log(11)
}
test()

执行后可以发现从1到11按顺序输出,同步执行。

列举一些异步任务

setTimeout(() => {
  console.log(1)
}, 1000)
Promise.resolve(2).then((i) => {
  console.log(i)
})
console.log(3)

可以看到输出顺序是 3 2 1

异步任务

异步任务又分为微任务宏任务

微任务有这些:

宏任务有这些:

  • script(整体代码)
  • setTimeout
  • setInterval
  • I/O 操作
  • setImmediate(Node)
  • requestAnimationFrame

流程

image.png

流程是这样的:

  • 加载script代码
  • 区分同步任务和异步任务
  • 主线程先执行同步任务,形成一个执行栈,如果遇到异步任务,区分是宏任务还是微任务,把它的回调压入各自的任务队列
  • 主线程执行完同步任务后,检查异步任务队列,先执行微任务,执行完微任务队列再执行宏任务队列;
  • 重复上面的过程

微任务先于宏任务执行

下面通过例子来分析下:

async function async1() {
  console.log('async1 start');
  await async2();
  console.log('async1 end');
}
async function async2() {
  console.log('async2');
}

console.log('script start');

setTimeout(function() {
  console.log('setTimeout');
}, 0);

async1();

new Promise(function(resolve) {
  console.log('promise1');
  resolve();
}).then(function() {
  console.log('promise2');
}).then(function() {
  console.log('promise3');
});

console.log('script end');

输出顺序是:

  • script start
  • async1 start
  • async2
  • promise1
  • script end
  • async1 end
  • promise2
  • promise3
  • setTimeout

你做对了吗?

分析:

  • 首先先把同步任务先执行, 输出script start'
  • 然后遇到setTimeout,把它压入异步宏任务中
  • 然后执行async1, 输出async1 start, 接着看到async2, 先执行async2, 因为它内部是同步任务,直接输出async2,因为它async2是await函数,所以把后面的代码压入异步微任务中
  • 然后遇到Promise, resolve之前是同步的,输出promise1, 把then部分放到异步微任务中
  • 然后遇到同步代码,输出script end
  • 主线程任务都执行完了后,接着执行异步微任务队列,输出 async1 end, promise2, promise3
  • 微任务队列执行完后,执行宏任务队列,输出setTimeout

浏览器和Node的事件循环有何区别

浏览器环境和Node环境,微任务任务队列的执行时机不同。

  • 浏览器环境,微任务任务队列是在宏任务之中执行;
  • Node环境, 微任务任务队列是在事件循环的各个阶段之间执行

总结

以上就是我总结的事件循环(Event Loop),希望对你们理解有所帮助~