面试题答案
一键面试执行顺序
- 初始状态:JavaScript 引擎首次启动时,调用栈为空,微任务队列和宏任务队列初始也为空。
- 宏任务执行:引擎从宏任务队列中取出一个宏任务,放入调用栈执行。在执行过程中,可能会产生新的宏任务和微任务。
- 微任务执行:宏任务执行完毕后,引擎会检查微任务队列,将微任务队列中的所有任务依次取出放入调用栈执行,直到微任务队列为空。
- 循环:重复上述 2、3 步骤,不断从宏任务队列中取任务执行,执行完后处理微任务队列,形成事件循环。
示例说明
setTimeout
(宏任务):
console.log('script start');
setTimeout(() => {
console.log('setTimeout');
}, 0);
console.log('script end');
在这段代码中,首先输出 script start
,然后输出 script end
。因为 setTimeout
是宏任务,会被放入宏任务队列,而当前代码属于主宏任务,主宏任务执行完毕后,才会从宏任务队列中取出 setTimeout
回调并执行,所以最后输出 setTimeout
。
2. Promise.then
(微任务):
console.log('script start');
Promise.resolve()
.then(() => {
console.log('Promise.then');
});
console.log('script end');
这里先输出 script start
,接着输出 script end
。Promise.resolve()
立即解决,其 .then
回调会被放入微任务队列。主宏任务执行完毕后,会处理微任务队列,所以最后输出 Promise.then
。
3. 结合示例:
console.log('script start');
setTimeout(() => {
console.log('setTimeout1');
Promise.resolve()
.then(() => {
console.log('Promise.then in setTimeout1');
});
}, 0);
Promise.resolve()
.then(() => {
console.log('Promise.then1');
});
setTimeout(() => {
console.log('setTimeout2');
}, 0);
console.log('script end');
输出顺序为:script start
-> script end
-> Promise.then1
-> setTimeout1
-> Promise.then in setTimeout1
-> setTimeout2
。主宏任务先执行,输出 script start
和 script end
;然后处理微任务队列,输出 Promise.then1
;接着从宏任务队列取出第一个 setTimeout
执行,输出 setTimeout1
,在这个 setTimeout
执行过程中产生的微任务 Promise.then in setTimeout1
会在该宏任务执行完毕后加入微任务队列并执行;最后执行第二个 setTimeout
,输出 setTimeout2
。