浏览器的事件循环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);

绝大多数情况是

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

极少数情况下会出现

相关推荐
vipbic4 分钟前
中后台越做越乱后,我用插件化把它救回来了
前端·vue.js
Hyyy9 分钟前
Computer Use 适合做什么,不适合做什么——一次真实使用后的思考
前端
小和尚同志36 分钟前
前端 AI 单元测试思考与落地
前端·人工智能·aigc
invicinble2 小时前
c端系统,其实更像一个信息展示平台
前端
李姆斯3 小时前
管理是否可以被完全量化
前端·产品经理·团队管理
名字还没想好☜3 小时前
Next.js 中间件实战:鉴权、重定向与 A/B 分流
开发语言·前端·javascript·中间件·react·next.js
广州灵眸科技有限公司3 小时前
瑞芯微RV1126B开发板(EASY-EAI-PI2) INI文件操作
java·前端·javascript·网络·人工智能
江华森4 小时前
Web 开发基础:HTTP 与 REST
前端·网络协议·http
IT_陈寒5 小时前
Redis的KEYS命令把我搞崩溃了,改用SCAN才活过来
前端·人工智能·后端
Jackson__5 小时前
为什么 Agent 越聊越慢?聊聊 Context(上下文)管理
前端·agent·ai编程