一、浏览器事件循环


1、浏览器进程模型

1.1、何为进程

注:浏览器主要有上面三个进程,但不止这三个!

注:浏览器进程是主进程,网络进程和渲染进程都是主进程开启的。

所谓每秒把页面画60次,就是指帧率为60ms(FPS), 不停的在画,不停的在画,所以我们才会感觉流畅

注意:这里所看到的其它线程有比如用户点击按钮时用到的交互线程,或者开启定时器时用到的计时线程

同步处理任务

计时器的线程非常复杂,比渲染线程还复杂,我们这里知道我们平常用的计时器就是交给计时线程处理的就行了。

异步处理任务

解释:任务都是一样的,但是队列可以有多个,浏览器会根据任务的特点分到不同的队列里去,不同的队列,他们的执行顺序是有优先级的!!!!!!!!!

这里简单说下promise.then()内部的回调属于微队列,await console.log(1);console.log(1)是同步代码,但是后续就属于微队列了。其他的基本上都属于其它队列了。还有微队列 > 交互队列 > 延时队列,也就是说promise.then()的执行顺序要高于setTimeout

注意:学会画图,把几个队列都画出来,按顺序执行就行了!!

问:交互队列、延时队列、微队列、网络请求队列,谁的执行优先级高,排个顺序??

在浏览器中,执行优先级的顺序通常为:

  1. 微队列(Microtasks Queue):包括 Promise.then、MutationObserver 回调等。
  2. 交互队列(Interaction Queue):通常与用户事件有关,比如点击、输入等。
  3. 网络请求队列(Network Requests Queue):包括 fetch、XHR 请求等。
  4. 延时队列(Timers Queue):包括 setTimeout、setInterval 等。

执行顺序具体如下:

  1. 当一个事件循环开始时,微任务队列(或微队列)中的所有微任务将被依次执行,直到微任务队列为空。微任务的优先级最高。
  2. 接下来,用户交互事件优先处理。
  3. 然后处理网络请求完成后的回调(如 AJAX 完成后处理)。
  4. 最后处理延时任务,比如 setTimeout 和 setInterval 的回调。

总结的顺序是:

  1. 微队列
  2. 交互队列
  3. 网络请求队列
  4. 延时队列

这样确保了关键的小任务(微任务)能够最快地得到响应,同时用户交互的事件也能迅速响应,网络请求的回调次之,最后才是延时任务。

JS引擎线程和渲染线程(GUI线程)是浏览器中两个非常重要的线程,它们在浏览器的多线程架构中协同工作,共同负责网页的加载、渲染和交互。理解它们之间的关系对于深入理解浏览器的工作原理至关重要。

2、js引擎线程和渲染线程

2.1、JS引擎线程

  • 功能:主要负责解析和执行JavaScript代码。
  • 特点
  • 单线程执行:同一时间只能执行一个JavaScript任务。
  • 处理异步操作:通过事件循环机制处理异步任务(如定时器、网络请求等)。

2.2、渲染线程(GUI线程)

  • 功能:负责页面的渲染工作,包括解析HTML和CSS、构建DOM树、计算布局、绘制页面等。
  • 特点
  • 与JS引擎线程互斥:当JS引擎线程执行JavaScript代码时,渲染线程会被阻塞,无法进行页面渲染。
  • 高效渲染:通过分阶段渲染(如重排、重绘)优化性能。

2.3、它们之间的关系

  1. 互斥关系
  • 阻塞现象:当JS引擎线程在执行JavaScript代码时,渲染线程会被阻塞,无法进行页面的渲染。这是因为JavaScript代码可能会修改DOM或样式,导致页面需要重新渲染。
  • 执行顺序:通常情况下,JS引擎线程先执行JavaScript代码,完成后渲染线程才会进行页面渲染。
  1. 协同工作
  • 事件循环:JS引擎线程通过事件循环机制处理异步任务,当执行栈中的同步代码执行完毕后,会从任务队列中取出异步任务的回调函数继续执行,期间渲染线程会在适当的时候进行页面渲染。
  • 异步更新:通过异步操作(如setTimeoutPromise等),JS引擎线程可以在不阻塞渲染线程的情况下,安排后续的DOM更新和页面渲染。
  1. 优化策略
  • 批量更新:现代浏览器通过批量更新DOM和样式,减少重排和重绘的次数,提高渲染效率。
  • Web Workers:使用Web Workers可以在后台线程中执行JavaScript代码,避免阻塞主线程(JS引擎线程和渲染线程)。

2.4、示例说明

// 同步JavaScript代码
console.log('开始执行JS代码');
document.body.innerHTML = '<p>新的内容</p>'; // 修改DOM

// 异步JavaScript代码
setTimeout(() => {
  console.log('异步任务执行');
  document.body.style.color = 'red'; // 修改样式
}, 1000);

console.log('继续执行JS代码');
javascript复制代码
  • 执行过程
  1. JS引擎线程开始执行同步代码,修改DOM。
  2. 同步代码执行完毕后,渲染线程进行页面渲染,显示新的内容。
  3. setTimeout将异步任务交给定时器线程处理,JS引擎线程继续执行后续代码。
  4. 异步任务完成后,其回调函数被放入任务队列。
  5. JS引擎线程在事件循环中取出并执行回调函数,再次修改样式。
  6. 渲染线程根据新的样式重新渲染页面。

2.5、总结

JavaScript是单线程的,意味着它一次只能执行一个任务。当JS引擎线程在执行JS代码时,它会占用主线程的全部资源,无法同时进行其他操作。

由于JS引擎线程和GUI渲染线程共享同一个主线程资源,当JS引擎线程在执行时,GUI渲染线程必须等待,无法同时进行页面渲染。

JS引擎线程和渲染线程在浏览器中紧密协作,但又互斥运行。JS引擎线程负责执行JavaScript代码,可能会触发渲染线程进行页面更新;而渲染线程在JS引擎线程执行代码时会暂时被阻塞,以避免渲染不一致的问题。通过事件循环和异步处理机制,浏览器能够在保证页面正确渲染的同时,高效地执行JavaScript代码。


文章作者: 吴俊杰
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 吴俊杰 !
 上一篇
二、浏览器的渲染原理 二、浏览器的渲染原理
曾经我不知道重绘和重排,只知道死记硬背,但是背了忘,忘了背,知道我开始去理解浏览器渲染过程,去了解它的每一步......
2024-12-04
下一篇 
四、项目权限梳理 四、项目权限梳理
公司的项目,梳理一下平台的登录流程、动态路由配置和跳转以及基于自定义指令v-has实现路由对应功能按钮权限的实现......
2024-12-04
  目录