关于宏任务/微任务,同步/异步的执行顺序的面试题

811 阅读2分钟

请写出下面代码的输出结果

async function promise1() {
    console.log("promise1  start")
    await promise2()
    console.log("promise1  end")
}
function promise2() {
    console.log("promise2")
}
setTimeout(function () {
    console.log("setTimeout")
}, 0)
console.log("script start")
promise1()
new Promise((resolve, reject) => {
    console.log("Promise")
    resolve()
}).then(function () {
    console.log("Promise then")
})
console.log("script end")

解析:

  • 宏任务/微任务
  • 事件循环
  • promise, async/await

宏任务/微任务

参考这个作者的js中的宏任务和微任务

宏任务包含

script(整体代码)
setTimeout
setInterval
I/O
UI交互事件
postMessage
MessageChannel
setImmediate(Node.js 环境)

微任务包含

Promise.then
Object.observe(将要废弃)
MutaionObserver(新特性)
process.nextTick(Node.js 环境)

事件循环

这个大大讲的比较详细,大家可以去看看。详解事件循环机制

  • js是单线程,一个线程拥有唯一一个时间循环,但任务队列可以有多个。
  • 任务队列又分为宏任务和微任务。
  • 来自不同任务源的任务会进入到不同的任务队列。(setTimeout与setInterval是同源的)
  • 事件循环的顺序,决定了JavaScript代码的执行顺序。它从script(整体代码)开始进入第一次循环,代码一行一行执行,执行过程中遇到宏任务,把宏任务加到宏任务队列中, 遇到微任务放到微任务队列中,当宏任务的函数调用栈执全部执行后,去看有没有微任务, 如果有,去执行微任务, 微任务全部执行完成后,循环再次从宏任务开始,这样循环。
  • 浏览器为了能够使得JS内部(macro)task与DOM任务能够有序的执行,会在一个(macro)task执行结束后,在下一个(macro)task 执行开始前,对页面进行重新渲染,流程:宏任务->微任务->渲染->宏任务->微任务->渲染->...

微信图片_20210426111700.png

promise, async/await

  • promise是同步的,它里面的代码会同步执行。
  • promise.then是微任务,promise.then里面的代码放到微任务队列中,等宏任务执行完成之后执行。
  • async/await 是同步语法,解决异步回调问题,promise.then.catch 链式调用,但也是基于回调函数的。
  • await会等待一个函数的执行结果,这个函数式同步的
  • await下面的代码相当于promise.then也会放到微任务队列中。

揭晓答案

async function promise1() {
    console.log("promise1  start")
    await promise2()
    console.log("promise1  end")
}
function promise2() {
    console.log("promise2")
}
setTimeout(function () {
    console.log("setTimeout")
}, 0)
console.log("script start")
promise1()
new Promise((resolve, reject) => {
    console.log("Promise")
    resolve()
}).then(function () {
    console.log("Promise then")
})
console.log("script end")

------------------------------------
script start
promise1  start
promise2
Promise
script end
promise1  end
Promise then
setTimeout