event loop 学习

160 阅读2分钟

异步执行机制

  • (1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
  • (2)主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
  • (3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
  • (4)主线程不断重复上面的第三步。

宏任务(task)与微任务(job)

宏任务有:

  • setTimeout,
  • setInterval,
  • setImmediate (Node独有),
  • requestAnimationFrame (浏览器独有),
  • I/O,
  • UI rendering (浏览器独有)

微任务有:

  • process.nextTick (Node独有)
  • Promise
  • Object.observe
  • MutationObserver

event loop

1 执行所有的同步script语句,碰到回调函数等异步语句时放入相应的任务队列(宏、微)

2 当当前执行栈为空时,才会去处理异步任务:

3 先将微任务队列清空,在执行微任务时新产生的微任务会立即被加入微任务队列并清空

4 再执行宏队列中的任务,若在执行宏任务时产生新的微任务,会加入微队列中并在每个宏任务执行的间隙清空当前微队列

执行机制

栗子

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

setTimeout(() => { //宏任务
  console.log(2);
  Promise.resolve().then(() => { //执行宏任务时产生的微任务
    console.log(3)
  });
});

new Promise((resolve, reject) => {
  console.log(4)  //同步任务
  resolve(5)
}).then((data) => {
  console.log(data);  //微任务
  
  Promise.resolve().then(() => {
    console.log(6)  //微任务
  }).then(() => {
    console.log(7)  //微任务
    
    setTimeout(() => {
      console.log(8)    //微任务里的宏任务
    }, 0);
  });
})

setTimeout(() => {
  console.log(9);   //宏任务
})

console.log(10);    //同步任务

顺序:所有同步任务=>当前微任务队列=>一个宏任务=>当前微任务队列=>...=>执行栈为空

结果:1,4,10,5,6,7,2,3,9,8

nodejs中的宏队列与微队列

NodeJS中宏队列主要有4个,回调事件主要位于4个macrotask queue中:

  • Timers Queue
  • IO Callbacks Queue
  • Check Queue
  • Close Callbacks Queue

NodeJS中微队列主要有2个:

  • Next Tick Queue:是放置process.nextTick(callback)的回调任务的
  • Other Micro Queue:放置其他microtask,比如Promise等

event loop过程:

1 执行所有的同步代码

2 执行栈为空时,执行微队列,先执行所有Next Tick Queue中的所有任务,再执行Other Microtask Queue中的所有任务。

3 微队列清空后开始执行宏队列,每次执行一个宏队列,间隙中执行当前微队列

4 顺序:同步任务=>两个微队列=>Timers Queue ->两个微队列-> I/O Queue -> 两个微队列 -> Check Queue -> 两个微队列 -> Close Callback Queue -> 两个微队列 -> Timers Queue ......