事件循环、Promise、async / await 怎么执行
先理解原理和示例,再练习完整口述与追问。
回答要点
浏览器中先执行当前同步任务,在微任务检查点处理微任务;渲染还取决于浏览器的渲染机会,不是每个任务结束都重绘。await 之后的继续执行具有异步调度行为,Promise 构造器执行器本身同步执行。
不要把浏览器和 Node 的调度规则混用;微任务不断追加也可能阻塞渲染。MDN:JavaScript 执行模型
原理拆解
先区分执行回调与登记回调:Promise 构造器中的 executor 立即同步执行,then 登记的反应稍后进入微任务;async 函数先同步执行到第一个 await,await 后续部分通过 Promise 调度恢复。浏览器完成一个任务后会检查微任务,清空后才有机会进行渲染和后续任务。定时器满足延迟条件只意味着可以被调度,不保证此刻立即执行。
示例与推演
console.log('A')
setTimeout(() => console.log('B'), 0)
Promise.resolve().then(() => console.log('C'))
async function run() {
console.log('D')
await 0
console.log('E')
}
run()
console.log('F')
// 常见浏览器中:A D F C E B
同步阶段输出 A、D、F;先登记 C,再登记 await 的继续执行 E,最后轮到定时器 B。
易错点
不要把所有异步都叫宏任务,也不要认为 await 会阻塞整个线程。递归排入微任务可能持续占用主线程;Node 还存在 nextTick 和不同事件循环阶段,不能直接套用浏览器输出。
参考回答可直接练习口述
浏览器先执行当前任务的同步调用栈,栈清空并到达微任务检查点后处理微任务,执行期间新加入的微任务也要继续处理。Promise 构造器的执行器同步执行,then 回调异步执行;await 会暂停当前 async 函数,后续代码经异步调度继续。定时器到时只是具备排队条件,不保证精确时间。渲染由浏览器决定合适机会,不是每个任务结束都必然绘制;无限追加微任务也会让界面卡住。