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

绝大多数情况是

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

极少数情况下会出现

相关推荐
0思必得06 小时前
[Web自动化] Selenium处理动态网页
前端·爬虫·python·selenium·自动化
东东5166 小时前
智能社区管理系统的设计与实现ssm+vue
前端·javascript·vue.js·毕业设计·毕设
catino6 小时前
图片、文件的预览
前端·javascript
测试涛叔8 小时前
金三银四软件测试面试题(800道)
软件测试·面试·职场和发展
layman05288 小时前
webpack5 css-loader:从基础到原理
前端·css·webpack
半桔8 小时前
【前端小站】CSS 样式美学:从基础语法到界面精筑的实战宝典
前端·css·html
AI老李8 小时前
PostCSS完全指南:功能/配置/插件/SourceMap/AST/插件开发/自定义语法
前端·javascript·postcss
_OP_CHEN9 小时前
【前端开发之CSS】(一)初识 CSS:网页化妆术的终极指南,新手也能轻松拿捏页面美化!
前端·css·html·网页开发·样式表·界面美化
啊哈一半醒9 小时前
CSS 主流布局
前端·css·css布局·标准流 浮动 定位·flex grid 响应式布局
PHP武器库9 小时前
ULUI:不止于按钮和菜单,一个专注于“业务组件”的纯 CSS 框架
前端·css