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

绝大多数情况是

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

极少数情况下会出现

相关推荐
万少44 分钟前
HarmonyOS 开发必会 5 种 Builder 详解
前端·harmonyos
哈里谢顿2 小时前
1000台裸金属并发创建中的重难点问题分析
面试
哈里谢顿2 小时前
20260303面试总结(全栈)
面试
橙序员小站3 小时前
Agent Skill 是什么?一文讲透 Agent Skill 的设计与实现
前端·后端
炫饭第一名5 小时前
速通Canvas指北🦮——基础入门篇
前端·javascript·程序员
王晓枫6 小时前
flutter接入三方库运行报错:Error running pod install
前端·flutter
符方昊6 小时前
React 19 对比 React 16 新特性解析
前端·react.js
ssshooter6 小时前
又被 Safari 差异坑了:textContent 拿到的值居然没换行?
前端
曲折6 小时前
Cesium-气象要素PNG色斑图叠加
前端·cesium
Forever7_6 小时前
Electron 淘汰!新的桌面端框架 更强大、更轻量化
前端·vue.js