event loop的执行顺序:

  • 一开始整个脚本作为一个宏任务执行
  • 执行过程中同步代码直接执行,宏任务进入宏任务队列,微任务进入微任务队列
  • 当前宏任务执行完出队,检查微任务列表,有则依次执行,直到全部执行完
  • 执行浏览器UI线程的渲染工作
  • 检查是否有Web Worker任务,有则执行
  • 执行完本轮的宏任务,执行宏任务队列的下一个,依此循环,直到宏任务和微任务队列都为空
微任务包括MutationObserverPromise.then()reject()Promise为基础开发的其它技术,比如fetch APIV8的垃圾回收过程、Node独有的process.nextTick
宏任务包括script、scriptsetTimeoutsetIntervalsetImmediateI/OUI rendering

下面是一道执行顺序的综合题

来自一个问答的题目

async function asyncl() {
  console.log('asyncl start')
  await async2()
  console.log('asyncl end')
}
async function async2() {
  console.log('async2 start')
  return new Promise((resolve, reject) =>{
    resolve()
    console.log('async2 promise')
  })
}
console.log('script start')
setTimeout(function() {
  console.log('setTimeout')
}, 0)
asyncl()
new Promise(function(resolve) {
  console.log('promise1')
  resolve()
}).then(function() {
  console.log('promise2')
}).then(function() {
  console.log('promise3')
})
console.log('script end')

event loop的执行顺序过程分析

  • 刚开始整个脚本作为第一次宏任务来执行,我们将它标记为宏1,从上至下执行
  • 遇到asyncl和async2函数先声明,执行同步代码console.log('script start')
  • 遇到setTimeout放到下一个宏任务队列
  • asyncl被调用,执行asyncl中的同步代码console.log('asyncl start')
  • 遇到await,后面代码被阻断,async2被调用,执行async2中的同步代码console.log('async2 start')
  • 遇到Promise,此时Promise被resolve()因此状态改为了resolved,执行Promise中的同步代码console.log('async2 promise'),async2执行完
  • 再遇到Promise,执行Promise中的同步代码console.log('promise1'),遇到Promise.resolve()状态改为了resolved
  • 跳出Promise,往下执行,碰到promise.then这个微任务,将其加入微任务队列1
  • 又碰到promise.then这个微任务,将其加入微任务队列2
  • 再执行同步代码console.log('script end'),到此处执行完,再回头执行微任务队列console.log('promise2')和console.log('promise3')
  • 最后回到await被阻断的代码执行console.log('asyncl end')
注意点: async函数中await后被阻断的代码,等待的时间是有限的,微任务执行队列不是无限制时间执行

总结

首先先按照顺序执行同步代码,再执行微任务队列(promise),回来看是否存在被await阻断的同步代码及微任务,执行完,再执行宏任务队列(setTimeout)。

个人的一些浅见,写的不好请轻喷!!!!欢迎一起交流!!!!


程序猿八哥
58 声望0 粉丝