JS事件循环

事件循环是单线程的Javascript在执行异步任务时进行的一种循环机制,最大的特点就是异步任务会被加入到事件队列中挂起,然后主线程在空闲的时候就回去检查事件队列,如果有挂起的事件则把它取出来到主线程执行。这个过程会循环进行,这就是事件循环。

我们来看一张图

从图中我们可以看出JS的执行除了主线程外还给异步线程开启了一个事件表,异步事件会先被加入事件表中,并且注册回调事件,回调事件存在于任务(事件)队列中。当主线任务全部执行完之后就会对任务队列进行判断,如果任务队列中有任务,那么将任务按顺序(先进先出)取出,并加入到主线程执行。此过程会一直循环直到程序退出。这就是事件循环。

宏任务和微任务

宏任务: script( 整体代码)、setTimeout、setInterval、I/O、UI 交互事件、setImmediate(Node.js 环境)

微任务: Promise、MutaionObserver、process.nextTick(Node.js 环境);

流程分析

  1. 先从宏任务队列中按顺序取一个任务
  2. 将任务中的所有微任务取出并按顺序全部执行
  3. 然后再重复以上操作,直至所有任务执行完成

代码:

console.log('code 1', 'code begin');
let sto = setTimeout(() => {
  console.log('code 2', 'in setTimeout');
  clearTimeout(sto);
}, 4);

new Promise((resolve) => {
  console.log('code 3', 'in new Promise')
  resolve();
}).then(() => {
  console.log('code 4', 'in Promise.then')
})
console.log('code 5', 'code end');

输出结果

code 1 code begin
code 3 in new Promise
code 5 code end
code 4 in Promise.then
code 2 in setTimeout

首先我们先分析哪些是同步执行的,依次为

  • code 1
  • code 3
  • code 5

所以这三个顺序确定,然后接下来的顺序为微任务的,那就是 promise.then 里的 code 4。再接下来才是宏任务 setTimeout() 里的 code 2

事情原来是这么个事情,那么为什么要有这种设计?

原因就在于两个字“插队”,引用一个博主的表达

当完成当下的宏任务后,会立刻执行所有在此期间入队的微任务。这种设计是为了给紧急任务一个插队的机会,否则新入队的任务永远被放在队尾。区分了微任务和宏任务后,本轮循环中的微任务实际上就是在插队,这样微任务中所做的状态修改,在下一轮事件循环中也能得到同步

未经允许不得转载