EventLoop执行机制

我心飞翔 分类:javascript

什么是EventLoop?

event loop是计算机系统的一种运行机制,JavaScript就采用这种机制,来解决单线程运行带来的一些问题。弄懂这个就能清楚的知道js到底是怎样去执行的。

MacroTask(宏任务)

  • setTimeout
  • setInterval
  • I/O
  • script代码块
  • setImmediate(浏览器暂时不支持,只有IE10支持,具体可见MDN)
  • UI Rendering

MicroTask(微任务)

  • nextTick
  • callback
  • Promise
  • process.nextTick
  • Object.observe(废弃)
  • MutationObserver

执行流程

Eventloop执行步骤

  1. 执行全局Script同步代码,这些同步代码有一些是同步语句,有一些是异步语句(比如setTimeout等)
  2. 全局Script代码执行完毕后,调用栈Stack会清空
  3. 从微队列microtask queue中取出位于队首的回调任务,放入调用栈Stack中执行,执行完后microtask queue长度减1
  4. 继续取出位于队首的任务,放入调用栈Stack中执行,以此类推,直到直到把microtask queue中的所有任务都执行完毕。注意,如果在执行microtask的过程中,又产生了microtask,那么会加入到队列的末尾,也会在这个周期被调用执行
  5. microtask queue中的所有任务都执行完毕,此时microtask queue为空队列,调用栈Stack也为空
  6. 取出宏队列macrotask queue中位于队首的任务,放入Stack中执行
  7. 执行完毕后,调用栈Stack为空
  8. 重复第3-7个步骤

简单点概括就是同步代码顺序执行,碰到微任务进微队列,碰到宏任务进宏队列。同步代码执行完先将微队列中的所有任务执行完,微队列执行过程中碰到的微任务放到队列尾部这次一并执行。微队列执行完毕后执行宏队列头部的任务,执行完成之后再进微队列,执行完所有的微任务,依次循环,直到所有任务执行完毕

例子1


console.log(1)

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

new Promise((resolve, reject) => {
  console.log(4)
  resolve(5)
}).then((res) => {
  console.log(res)
})

setTimeout(() => {
  console.log(6)
}, 0)

console.log(7)
// 输出结果1 4 7 5 2 3 6

 

例子2

Promise.resolve().then(() => {
  console.log('mm')
  Promise.resolve().then(() => {
    console.log('xx')
  }).then(() => {
    console.log('yy')
  })
}).then(() => {
  console.log('nn')
})
// 输出结果mm xx nn yy

 

这段代码的输出结果你猜对了吗?我们再来分析:

  1. 首先看代码中只有一个大promise,先执行,mm直接输出,promise进微队列,内部执行完毕
  2. 然后外层.then进微队列
  3. 执行微队列,输出xx,碰到内部.then加入队列尾部
  4. 输出nn
  5. 输出yy

这里关于Promise链式调用的规则

  • 如果前面的 promise 已经是 resolved 状态,则会立即将回调推入微任务队列(但是执行回调还是要等到所有同步任务都结束后)
  • 如果前面的 promise 是 pending 状态则会将回调存储在 promise 的内部,一直等到 promise 被 resolve 才将回调推入微任务队列
参考:

Promise 链式调用顺序引发的思考

一分钟带你弄懂Event loop

回复

我来回复
  • 暂无回复内容