浏览器的事件循环EventLoop

浏览器一帧做哪些事情

  1. js执行
  2. requestAnimationFrame回调
  3. 渲染
  4. requestIdleCallback回调

事件循环主要指的是js执行过程的事件循环

  1. 宏任务:setTimeout,setInterval,messageChannel,js代码块,输入输出操作,事件回调
  2. 微任务:Promise.then,.catch,.finally, async await, MutationObverser, queueMicrotask
  3. 动画队列:Animation callbacks, requestAnimationFrame

上代码

js 复制代码
console.log('1');

const channel = new MessageChannel();
channel.port1.onmessage = () => {
  console.log('2');
  setTimeout(() => console.log('3'), 0);
};
channel.port2.postMessage(null);

setTimeout(() => {
  console.log('4');
   Promise.resolve().then(() => console.log('5'));
}, 0);

async function async1() {
  console.log('6');
  await async2();
  console.log('7');
}

async function async2() {
  console.log('8');
  await Promise.resolve().then(() => console.log('9'));
  console.log('10');
}

Promise.resolve().then(() => {
  console.log('11');
});

async1();

new Promise(resolve => {
  console.log('12');
  resolve();
}).then(() => console.log('13'));

console.log('14');

解析执行过程

同步代码执行

  1. 输出1
  2. 产生messageChannel宏任务,放入宏任务队列
  3. 产生setTimeout宏任务,放入宏任务队列
  4. 产生.then微任务,放入微任务队列
  5. 执行async1函数,输出6 , 执行async2函数,输出8,产生一个微任务,放入微任务队列
  6. 返回继续执行同步代码,输出12, 产生一个微任务,放入微任务队列
  7. 输出14

同步代码执行完毕,处理微任务队列

  1. 输出11
  2. 输出9,产生新的微任务,放入微任务队列
  3. 输出13
  4. 将新产生的微任务取出执行,输出10
  5. 此时async2执行完毕,将saync2后面的代码放入微任务队列
  6. 取出微任务队列任务执行,输出7

微任务代码全部执行完毕,处理宏任务

  1. 取出messageChannel宏任务执行,输出2,产生宏任务,放入宏任务队列
  2. 取出setTimeout的宏任务执行,输出4,产生微任务,放入微任务队列
  3. 取出微任务执行,输出5
  4. 取出宏任务执行,输出3

总结

  1. messageChannel和setTimeout在浏览器端没有优先级顺序,谁先进入宏任务队列,谁先执行
  2. async,await的执行,await后面的代码同步执行,await下一行的代码,等到Promise状态变更以后,再放入微任务队列中
  3. 如果代码中嵌入了requestAnimationFrame回调,那么执行顺序将变得不固定,原因是得看浏览器当前正在处理一帧内的哪个阶段
  • 如果是js执行阶段,那么就会先执行setTimeout1和setTimeout2,再输出rAF
  • 如果是js执行阶段,并且js执行的剩余时间不太够的情况下,会先输出setTimeout1, 然后输出rAF,再下一帧的js执行阶段,再输出setTimeout2
  • 如果当前是requestAnimationFrame阶段,那么会先输入rAF,再下一帧输出setTimeout1和setTimeout2

验证结论1

验证结论3

js 复制代码
setTimeout(() => {
  console.log('setTimeout1');
}, 0);
requestAnimationFrame(() => {
  console.log("requestAnimationFrame");
});
setTimeout(() => {
  console.log('setTimeout2');
}, 0);

绝大多数情况是

少数情况会出现这样的结果

极少数情况下会出现

相关推荐
IT_陈寒17 分钟前
Vite热更新失灵?你可能漏了这个配置
前端·人工智能·后端
丷丩17 分钟前
MapLibre GL JS第19课:实时更新要素
前端·javascript·gis·map·mapbox·maplibre gl js
Mr.Daozhi21 分钟前
RAG 进阶实战:跑通 Demo 后我连续翻了 6 次车,逐一修复才真正可用(含 Gradio Web 版)
前端·数据库·langchain·大模型·gradio·rag·科研工具
哆来A梦没有口袋32 分钟前
干货精讲 | 初级CSS面试高频考题
前端·css·面试
plainGeekDev41 分钟前
Android运行时面试题:ART和JVM的区别都搞不清,别写精通了
jvm·面试·kotlin
Cosolar1 小时前
QwenPaw Agent 实现原理深度剖析
后端·面试·架构
掘金011 小时前
EmbedPDF Vue 版 完整正文文档 全网首发
前端
OpenTiny社区1 小时前
操作ArkTS页面跳转及路由相关心得
前端·typescript·web·opentiny
xiaohua0708day1 小时前
Lodash库
前端·javascript·vue.js
huakoh1 小时前
Claude Code 从零到上手指南:国产工具链复现80% Agent能力,DeepSeek+LangChain实战
前端