Babel的奇妙冒险[支线] 事件轮询(Event Loop)

554 阅读4分钟

Promise 执行顺序

console.log('1');
// setTimeout1
setTimeout(function() {
    console.log('2');
    // Promise2
    new Promise(function(resolve) {
        console.log('3');
        resolve();
    }).then(function() {
        console.log('4')
        // Promise3
        new Promise(function(resolve) {
            console.log('5');
            // setTimeout3
            setTimeout(function() {
                console.log('6');
                resolve();
            })
        }).then(function() {
            console.log('7')
        })
    })
})

// Promise1
new Promise(function(resolve) {
    console.log('8');
    resolve();
}).then(function() {
    console.log('9')
})

// setTimeout2
setTimeout(function() {
    console.log('10');
    // Promise4
    new Promise(function(resolve) {
        console.log('11');
        // setTimeout4
        setTimeout(function() {
            console.log('12')
        })
    }).then(function() {
        console.log('13')
    })
})
console.log('14');

// 答案
// 1 8 14 9 2 3 4 5 10 11 6 7 12

执行规则描述

  • 异步事件返回结果后会被放在异步任务队列中,根据类型会放在宏任务或微任务队列
    • new Promie的(resolve,reject) => {} 部分, 属于同步代码
    • 当 Promise resolve(状态 pending -> fulfilled),Promise 的 then(() => {}) 处理会放在微任务中
    • 同理 Promise rejected(状态 pending -> rejected),Promise 的 catch(() => {}) 处理会放在微任务中
  • 当前执行栈为空时,先检查微任务是否存在,如果不存在再去检查宏任务

执行解答

  • 初始状态
    • 微任务队列:空
    • 宏任务队列:空
  • 当前执行栈:主线代码
    • 输出 1
    • setTimeout1 放入宏任务队列
    • Promise1 中的同步代码执行
      • 输出 8
      • Promise1 resolve,then 回调放入微任务队列
    • setTimeout2 放入宏任务队列
    • 输出 14
  • 当前状态
    • 微任务队列:[ Promise1.then ]
    • 宏任务队列:[ setTimeout1, setTimeout2 ]
  • 当前执行栈: Promise1.then
    • 输出 9
  • 当前状态
    • 微任务队列:[]
    • 宏任务队列:[ setTimeout1, setTimeout2 ]
  • 当前执行栈: setTimeout1
    • 输出 2
    • 执行 Promise2 中的同步代码
      • 输出 3
      • Promise2 resolve,then 回调放入微任务队列
  • 当前状态
    • 微任务队列:[ Promise2.then ]
    • 宏任务队列:[ setTimeout2 ]
  • 当前执行栈: Promise2.then
    • 输出 4
    • 执行 Promise3 中的同步代码
      • 输出 5
      • setTimeout3 放入宏任务队列
  • 当前状态
    • 微任务队列:[ ]
    • 宏任务队列:[ setTimeout2, setTimeout3 ]
  • 当前执行栈: setTimeout2
    • 输出 10
    • 执行 Promise4 中的同步代码
      • 输出 11
      • setTimeout4 放入宏任务队列
  • 当前状态
    • 微任务队列:[ ]
    • 宏任务队列:[ setTimeout3, setTimeout4 ]
  • 当前执行栈: setTimeout3
    • 输出 6
    • Promise3 resolve,then 回调放入微任务队列
  • 当前状态
    • 微任务队列:[ Promise3.then ]
    • 宏任务队列:[ setTimeout4 ]
  • 当前执行栈: Promise3.then
    • 输出 7
  • 当前状态
    • 微任务队列:[]
    • 宏任务队列:[ setTimeout4 ]
  • 当前执行栈: setTimeout4
    • 输出 12

Promise4 状态一直是 pending, 所以12不会输出

await 执行顺序

async function async1 () {
  console.log(1)

  // Promise1
  new Promise((resolve) => {
    console.log(2)
    resolve();
  }).then(function() {
    console.log(3)
  })

  // Promise2
  await new Promise((resolve) => {
    console.log(5)
    resolve();
  }).then(() => {
    console.log(6)
  })

  // await 1
  console.log(7)

  // Promise5
  new Promise((resolve) => {
    console.log(8)
    resolve();
  }).then(() => {
    console.log(9)
  })
}

// setTimeout1
setTimeout(() => {
  console.log(10)
})

async function async2() {
  console.log(11)
  // Promise4
  await Promise.resolve().then(() => {
     console.log(12)
  })
  // await2
  console.log(13)
}

async1()

// Promise3
new Promise((resolve) => {
  console.log(14)
  resolve();
}).then(() => {
  console.log(15)
})

async2()

console.log(16);

// 答案
// 1 2 5 14 11 16 3 6 15 12 7 8 13 9 10

执行规则描述

  • 执行遇到 await 让出线程, 阻塞后面代码
  • await 语句是同步的,await 语句后面全部代码才是异步的微任务
  • 只有运行完 await 语句,才把 await 语句后面的全部代码加入到微任务行列
  • 在遇到 await promise 时,必须等 await promise 函数执行完毕才能对 await 语句后面的全部代码加入到微任务中
    • await 会暂停 async 后面的代码,先执行async外面的同步代码,等着 Promise 对象 fulfilled,然后把 resolve 的参数作为 await 表达式的运算结果
  • 如果 await 后面不是promise, await会阻塞后面的代码, 先执行 async 外面的同步代码, 同步代码执行完毕后, 在回到async内部

执行解答

  • 初始状态
    • 微任务队列:空
    • 宏任务队列:空
  • 当前执行栈:主线代码
    • 函数声明 async1
    • setTimeout1 放入宏任务队列
    • 函数申明 async2
    • 执行 async1()
    • 输出 1
    • 执行 Promise1 中的同步代码
      • 输出 2
      • resolve, Promise1.then 放入微任务队列
    • await Promise2
      • 执行 Promise2 中的同步代码
      • 输出 5
      • resolve, Promise2.then 放入微任务队列
      • await 让出线程
    • 执行 Promise3 中的同步代码
      • 输出 14
      • resolve, Promise3.then 放入微任务队列
    • 执行 async2()
      • 输出 11
      • Promise4 resolve, Promise4.then 放入微任务队列
      • await 让出线程
    • 输出 16
  • 当前状态
    • 微任务队列:[ Promise1.then, Promise2.then, Promise3.then, Promise4.then ]
    • 宏任务队列:[ setTimeout1 ]
  • 当前执行栈: Promise1.then
    • 输出 3
  • 当前状态
    • 微任务队列:[ Promise2.then, Promise3.then, Promise4.then ]
    • 宏任务队列:[ setTimeout1 ]
  • 当前执行栈: Promise2.then
    • 输出 6
    • await1 后续代码放入微任务队列
  • 当前状态
    • 微任务队列:[ Promise3.then, Promise4.then, await1 ]
    • 宏任务队列:[ setTimeout1 ]
  • 当前执行栈: Promise3.then
    • 输出 15
  • 当前状态
    • 微任务队列:[ Promise4.then, await1 ]
    • 宏任务队列:[ setTimeout1 ]
  • 当前执行栈: Promise4.then
    • 输出 12
    • await2 后续代码放入微任务队列
  • 当前状态
    • 微任务队列:[ await1, await2 ]
    • 宏任务队列:[ setTimeout1 ]
  • 当前执行栈: await1
    • 输出 7
    • 执行 Promise5 中的同步代码
    • 输出 8
    • resolve, Promise5.then 放入微任务队列
  • 当前状态
    • 微任务队列:[ await2, Promise5.then ]
    • 宏任务队列:[ setTimeout1 ]
  • 当前执行栈: await2
    • 输出 13
  • 当前状态
    • 微任务队列:[ Promise5.then ]
    • 宏任务队列:[ setTimeout1 ]
  • 当前执行栈: Promise5.then
    • 输出 9
  • 当前状态
    • 微任务队列:[ ]
    • 宏任务队列:[ setTimeout1 ]
  • 当前执行栈: setTimeout1
    • 输出 10