面试题答案
一键面试事件循环过程及微任务队列变化情况
- 网络请求阶段:网络请求发起,这是一个异步操作,它不会阻塞主线程,JavaScript 引擎继续执行后续代码。
- Promise 回调执行:当网络请求完成,其对应的 Promise 的
then
回调会被放入微任务队列。此时,如果当前执行栈为空,事件循环会从微任务队列中取出这个回调并放入执行栈执行。 - 新 Promise 创建及微任务添加:在
then
回调中创建新的 Promise 并添加微任务(例如使用Promise.resolve().then()
),新的微任务会被添加到微任务队列的末尾。 - 事件循环继续:当前执行栈中的
then
回调执行完毕后,事件循环再次检查微任务队列,若有任务则依次取出放入执行栈执行。新添加的微任务会按顺序执行。只有当微任务队列清空后,事件循环才会去检查宏任务队列,取出下一个宏任务放入执行栈执行。
可能出现的性能问题
- 微任务过多阻塞主线程:如果在 Promise 回调中频繁创建新的 Promise 并添加微任务,微任务队列可能会积累大量任务,导致主线程长时间被占用,影响页面的渲染和用户交互响应。
- 内存泄漏风险:过多未处理的 Promise 回调以及微任务可能导致内存占用不断增加,引发内存泄漏问题。
优化方法
- 减少微任务创建频率:避免在 Promise 回调中不必要地创建新的 Promise 和添加微任务,尽量合并操作,减少微任务数量。
- 使用
requestIdleCallback
:对于一些非紧急的任务,可以使用requestIdleCallback
把任务放到浏览器空闲时段执行,避免阻塞主线程。 - 合理处理 Promise:确保 Promise 链的长度合理,及时释放不再使用的 Promise 引用,防止内存泄漏。同时,避免在 Promise 中进行过于复杂和耗时的同步操作。