Skip to content

事件循环

总结:事件循环是 JS 的运行机制,JS 是单线程的,意味着所有任务都需要排队依次执行,前一个任务未完成时后续任务不能被执行。为了解决任务阻塞后续任务执行就有了同步和异步任务,异步任务交给其他线程中处理,当异步任务需要执行将其放到主线程中执行。事件循环具体流程....

​ 了解事件循环需要先知道 JS 为什么拥有事件循环机制,看看 JS 拥有事件循环的历史原因。

1.JS 是单线程的

单线程意味着 Web 应用的所有代码都是在一个线程中运行的,同一时间只能做一件事情。为什么不能是多线程的?因为 JS 是需要操作 DOM 的,若某个线程通过 DOM 删除了一个元素而另一个线程有在这个元素中添加了子元素,那么浏览器以哪个线程的操作为准?为了降低复杂性,所以 JS 只能是单线程的。

2.任务队列

​ 单线程就意味着所有任务都需要排队执行,前一个任务结束,后面的任务才能执行。若前一个任务耗费事件长,后续任务也需要等待前一个任务完成才能被执行。例如网络请求,就需要等待响应成功才能执行后续任务,会导致后续任务的阻塞。

JavaScript 语言的设计者意识到,这时主线程完全可以不管 IO 设备,挂起处于等待中的任务,先运行排在后面的任务。等到 IO 设备返回了结果,再回过头,把挂起的任务继续执行下去。

后来,JS 有了同步任务、异步任务的把原先的任务区分开来:

同步任务:主线程中排队执行的任务,只有前一个同步任务完成,才能执行后续同步任务。

异步任务:异步任务不会阻塞同步任务的执行,会将异步任务放到浏览器其他线程中处理,当异步任务有了结果后,会将其放到任务队列里等待主线程执行。

​ 任务队列:是用来存放异步任务的。

3.事件循环

​ 整个 JS 应用的执行流程如下:

  1. 主线程执行同步任务
  2. 遇到异步操作时将异步任务注册给event table,待合适时会入队到任务队列event queue
  3. 主线程同步任务执行完成,查看任务队列中是否有需要执行的任务
  4. 若有,出队然后执行一个任务;若无,执行完毕。
  5. 主线程不断重复步骤 3、4

整个执行流程就是指事件循环,事件循环就是 JS 的运行机制。

4.任务优先级

​ 在 node 环境下,任务是有优先级的:

js
process.nextTick()>Promise.then()>setTimeout>setImmediate。
process.nextTick()>Promise.then()>setTimeout>setImmediate。

​ 只需要知道nextTickthen注册的任务有更高优先级。

5.微任务须知

WARNING

​ 若在本次循环的某个微任务执行时,又创建了微任务,则这个新的微任务会添加到本次循环的微任务队尾中,等待执行。而不会将该微任务添加到下次循环的微任务队列中。

js
console.log("script start");

Promise.resolve().then(() => {
  console.log("then01");
  Promise.resolve().then(() => {
    console.log("then02");
  });
});

Promise.resolve().then(() => {
  console.log("then03");
});

setTimeout(() => {
  console.log("setTimeout");
  Promise.resolve().then(() => {
    console.log("then");
  });
});

console.log("script end");
console.log("script start");

Promise.resolve().then(() => {
  console.log("then01");
  Promise.resolve().then(() => {
    console.log("then02");
  });
});

Promise.resolve().then(() => {
  console.log("then03");
});

setTimeout(() => {
  console.log("setTimeout");
  Promise.resolve().then(() => {
    console.log("then");
  });
});

console.log("script end");

6.宏微任务相关 API

setTimeout、setInterval、requestAnimationFrame、IO 操作、UI 渲染

then、queueMicrotask、Observer、nextTick