面试题答案
一键面试JavaScript事件循环机制
- 事件循环定义:JavaScript是单线程语言,事件循环是其实现异步操作的核心机制。它不断检查调用栈是否为空,当调用栈为空时,从任务队列中取出任务放入调用栈执行,以此循环。
- 宏任务与微任务:
- 宏任务(macrotask):如
setTimeout
、setInterval
、setImmediate
(仅Node.js环境)、I/O
操作、UI渲染
等。 - 微任务(microtask):如
Promise.then
、MutationObserver
、process.nextTick
(仅Node.js环境)等。
- 宏任务(macrotask):如
- 协调方式:
- 事件循环首先执行栈中的同步任务,执行完后检查微任务队列,将微任务队列中的所有任务依次执行完,再去宏任务队列中取一个宏任务放入调用栈执行,执行完该宏任务后,又会再次清空微任务队列,如此循环。
实际Web开发场景中的宏任务和微任务
- 宏任务示例:
setTimeout
:
console.log('start');
setTimeout(() => {
console.log('setTimeout callback');
}, 0);
console.log('end');
// 输出:start -> end -> setTimeout callback
- **`I/O操作`**:如 `fetch` 请求,当请求完成后会将回调函数作为宏任务放入宏任务队列。
fetch('https://example.com/api')
.then(response => response.json())
.then(data => console.log(data));
// 发起请求后,主线程继续执行,当请求完成,回调函数进入宏任务队列等待执行
- 微任务示例:
Promise.then
:
console.log('start');
Promise.resolve()
.then(() => console.log('Promise.then callback'));
console.log('end');
// 输出:start -> end -> Promise.then callback
事件循环机制对代码执行顺序的影响
- 宏任务与同步任务顺序:同步任务优先执行,宏任务在同步任务执行完且调用栈为空后执行。如上述
setTimeout
示例,start
和end
先输出,setTimeout
回调在最后。 - 微任务与宏任务顺序:宏任务执行完后,会立即执行微任务队列中的所有任务,然后再执行下一个宏任务。例如:
console.log('start');
setTimeout(() => {
console.log('setTimeout callback');
Promise.resolve()
.then(() => console.log('Promise in setTimeout'));
}, 0);
Promise.resolve()
.then(() => console.log('Promise.then callback'));
console.log('end');
// 输出:start -> end -> Promise.then callback -> setTimeout callback -> Promise in setTimeout
先执行同步任务 start
和 end
,然后执行微任务队列中的 Promise.then callback
,接着执行宏任务 setTimeout callback
,之后执行 setTimeout
内部产生的微任务 Promise in setTimeout
。