事件循环

要点

  • 异步任务先注册再执行。尤须注意 Promise 多个 then 时微任务的注册顺序

  • then 微任务注册时机。碰到 then 时再注册,而非一看到 resolve 就立即注册,resolve 仅是确保该 then 微任务能够被注册

  • 遇到 await,会立即执行右边的语句,然后提前跳出 async 函数,待外部执行完毕后,再返回 async 函数内部继续执行未执行完的

习题 1

console.log('start')

setTimeout(() => {
  console.log('children2')
  Promise.resolve().then(() => {
    console.log('children3')
  })
}, 0)

new Promise(function(resolve, reject) {
  console.log('children4')
  setTimeout(function() {
    console.log('children5')
    resolve('children6')
  }, 0)
}).then(res =>{         
  console.log('children7')
  setTimeout(() => {
    console.log(res)
  }, 0)
})

// 输出
start
children4
children2
children3 
children5
children7 
children6

习题 2 hard

setTimeout(() => { // 宏 1
  console.log(0)
})

new Promise(resolve => {
  resolve()
  Promise.resolve().then(() => { // 微 1
    console.log(2)
    Promise.resolve().then(() => { // 微 3
      console.log(4)
    })
 })
 console.log(3)
}).then(() => { // 微 2
  console.log(1)
})

console.log(5)

// 输出
3、5、2、1、4、0

// 解析
script 整体作为一个宏任务开始执行
碰到 setTimeout,注册宏 1
碰到第一个 then,注册微 1
继续执行同步代码,输出 3
碰到第二个 then,注册微 2
继续执行同步代码,输出 5
script 整体宏任务执行完毕,检查微任务队列不为空,准备逐一执行
取出微 1,输出 2
碰到第三个 then,注册微 3
取出微 2,输出 1
取出微 3,输出 4
当前微任务队列所有微任务执行完毕,准备执行下一个宏任务
取出宏 1,输出 0
宏 1 执行完毕,检查微任务队列为空,则准备执行下一个宏任务,检查宏任务队列也为空,则事件循环结束

习题 3

console.log(1) 

setTimeout(() => { // 宏 1
  console.log(2)     
  Promise.resolve().then(() => { 微 4
    console.log(3)  
  })
})

new Promise((resolve, reject) => {
  console.log(4) 
  resolve(5)
}).then((data) => { // 微 1
  console.log(data)  
  Promise.resolve().then(() => { // 微 2
    console.log(6)  
  }).then(() => { // 微 3
    console.log(7)  
    setTimeout(() => { // 宏 3
      console.log(8)  
    }, 0)
  })
})

setTimeout(() => { // 宏 2
  console.log(9)     
})

console.log(10)

// 输出
1、4、10、5、6、7、2、3、9、8

// 解析
script 整体作为一个宏任务开始执行
执行同步代码,输出 1
碰到第一个 setTimeout,注册宏 1
继续执行同步代码,输出 4
碰到第一个 then,注册微 1
碰到第二个 setTimeout,注册宏 2
继续执行同步代码,输出 10
script 整体宏任务执行完毕,检查微任务队列不为空,准备逐一执行
取出微 1,输出 5
碰到第二个 then,注册微 2
取出微 2,输出 6
碰到第三个 then,注册微 3
取出微 3,输出 7
碰到第三个宏任务,注册宏 3
当前微任务队列所有微任务执行完毕,准备执行下一个宏任务
取出宏 1,输出 2
碰到第四个微任务,注册微 4
宏 1 执行完毕,检查微任务队列不为空,准备逐一执行
取出微 4,输出 3
当前微任务队列所有微任务执行完毕,准备执行下一个宏任务
取出宏 2,输出 9
宏 2 执行完毕,检查微任务队列为空,则准备执行下一个宏任务,检查宏任务队列不为空
取出宏 3,输出 8
宏 3 执行完毕,检查微任务队列为空,则准备执行下一个宏任务,检查宏任务队列也为空,则事件循环结束

习题 4 hard

var myPromise = Promise.resolve(Promise.resolve('Promise'))

function funcOne() {
  console.log('funcOne Start')
  myPromise.then(res => res).then(res => console.log('funcOne ' + res))
  setTimeout(() => console.log('funcOne Timeout'), 0)
  console.log('funcOne End')
}

async function funcTwo() {
  console.log('funcTwo Start')
  const res = await myPromise
  console.log(await 'funcTwo ' + res)
  setTimeout(() => console.log('funcTwo Timeout'), 0)
  console.log('funcTwo End')
}

funcOne()
funcTwo()

// 输出
funcOne Start
funcOne End
funcTwo Start
funcOne Promise
funcTwo Promise
funcTwo End
funcOne Timeout
funcTwo Timeout

习题组 1

习题一

new Promise((resolve, reject) => {
  console.log('外部 promise')
  resolve()
}).then(() => {
  console.log('外部第一个 then')
  return new Promise((resolve, reject) => {
    console.log('内部 promise')
    resolve()
  }).then(() => {
    console.log('内部第一个 then')
  }).then(() => {
    console.log('内部第二个 then')
  })
}).then(() => {
  console.log('外部第二个 then')
})

// 输出
外部 promise
外部第一个 then
内部 promise
内部第一个 then
内部第二个 then
外部第二个 then

习题二

new Promise((resolve, reject) => {
  console.log('外部 promise')
  resolve()
}).then(() => {
  console.log('外部第一个 then')
  new Promise((resolve, reject) => {
    console.log('内部 promise')
    resolve()
  }).then(() => {
    console.log('内部第一个 then')
  }).then(() => {
    console.log('内部第二个 then')
  })
}).then(() => {
  console.log('外部第二个 then')
})

// 输出
外部 promise
外部第一个 then
内部 promise
内部第一个 then
外部第二个 then
内部第二个 then

习题三

new Promise((resolve, reject) => {
  console.log('外部 promise')
  resolve()
}).then(() => {
  console.log('外部第一个 then')
  let p = new Promise((resolve, reject) => {
    console.log('内部 promise')
    resolve()
  })
  p.then(() => {
    console.log('内部第一个 then')
  })
  p.then(() => {
    console.log('内部第二个 then')
  })
}).then(() => {
  console.log('外部第二个 then')
})

// 输出
外部 promise
外部第一个 then
内部 promise
内部第一个 then
内部第二个 then
外部第二个 then

习题四 hard

let p = new Promise((resolve, reject) => {
  console.log('外部 promise')
  resolve()
})
p.then(() => {
  console.log('外部第一个 then')
  new Promise((resolve, reject) => {
    console.log('内部 promise')
    resolve()
  }).then(() => {
    console.log('内部第一个 then')
  }).then(() => {
    console.log('内部第二个 then')
  })
})
p.then(() => {
  console.log('外部第二个 then')
})

// 输出
外部 promise
外部第一个 then
内部 promise
外部第二个 then
内部第一个 then
内部第二个 then

习题五 hard

new Promise((resolve, reject) => {
  console.log('外部 promise')
  resolve()
}).then(() => {
  console.log('外部第一个 then')
  new Promise((resolve, reject) => {
    console.log('内部 promise')
    resolve()
  }).then(() => {
    console.log('内部第一个 then')
  }).then(() => {
    console.log('内部第二个 then')
  })
  return new Promise((resolve, reject) => {
    console.log('内部 promise2')
    resolve()
  }).then(() => {
    console.log('内部第一个 then2')
  }).then(() => {
    console.log('内部第二个 then2')
  })
}).then(() => {
  console.log('外部第二个 then')
})

// 输出
外部 promise
外部第一个 then
内部 promise
内部 promise2
内部第一个 then
内部第一个 then2
内部第二个 then
内部第二个 then2
外部第二个 then

习题组 2

习题一

async function async1() {
  console.log('async1 start')
  await async2()
  console.log('async1 end')
}

async function async2() {
  console.log('async2')
}

console.log('script start')

setTimeout(function () {
  console.log('setTimeout')
}, 0)

async1()

new Promise((resolve) => {
  console.log('promise1')
  resolve()
}).then(function () {
  console.log('promise2')
})

console.log('script end')

// 输出
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout

习题二

async function async1() {
  console.log('async1 start')
  await async2()
  console.log('async1 end')
}

async function async2() {
  new Promise(function (resolve) {
    console.log('promise1')
    resolve()
  }).then(function () {
    console.log('promise2')
  })
}

console.log('script start')

setTimeout(function () {
  console.log('setTimeout')
}, 0)

async1()

new Promise(function (resolve) {
  console.log('promise3')
  resolve()
}).then(function () {
  console.log('promise4')
})

console.log('script end')

// 输出
script start
async1 start 
promise1
promise3 
script end 
promise2
async1 end
promise4
setTimeout

习题三 hard

async function async1() {
  console.log('async1 start')
  await async2()
  setTimeout(function() {
    console.log('setTimeout1')  
  }, 0)
}

async function async2() {
  setTimeout(function() {
    console.log('setTimeout2')
  }, 0)
}

console.log('script start')

setTimeout(function() {
  console.log('setTimeout3')
}, 0)

async1()

new Promise(function(resolve) {
  console.log('promise1')
  resolve()
}).then(function() {
  console.log('promise2')
})

console.log('script end')

// 输出
script start
async1 start
promise1
script end
promise2
setTimeout3
setTimeout2
setTimeout1
Last Updated:
Contributors: Vsnoy