浏览器渲染机制

进程和线程

  • 进程时cpu资源分配的最小单位,是能拥有资源和独立运行的最小的单位。
  • 线程是cpu调度的最小单位,是建立在进程基础上的一次程序运行单位。
  • 对于操作系统来说,一个任务就是一个进程,一个进程至少有一个线程

浏览器的多进程架构

image

主进程

负责浏览器界面的显示与交互。各个页面的管理,创建和销毁其他进程。网络的资源管理、下载等。

第三方插件进程

每种类型的插件对应一个进程,仅当使用该插件时才创建。

GPU 进程

最多只有一个,用于 3D 绘制等

渲染进程

称为浏览器渲染进程或浏览器内核,内部是多线程的。主要负责页面渲染,脚本执行,事件处理等。

渲染进程

浏览器的渲染进程是多线程的
image

GUI 渲染线程

  • 负责渲染浏览器界面,解析 HTML、CSS,构建 DOM 树和 RenderObject 树,布局和绘制等。
  • 当界面需要重绘(Repaint)或由于某种操作引发回流(reflow)时,该线程就会执行。
  • 注意,==GUI 渲染线程与 JS 引擎线程是互斥的==,当 JS 引擎执行时 GUI 线程会被挂起(相当于被冻结了),GUI 更新会被保存在一个队列中等到 JS 引擎空闲时立即被执行。

JS 引擎线程

  • Javascript 引擎,也称为 JS 内核,负责处理 Javascript 脚本程序。(例如 V8 引擎)
  • JS 引擎线程负责解析 Javascript 脚本,运行代码。
  • JS 引擎一直等待着任务队列中任务的到来,然后加以处理,一个 Tab 页(renderer 进程)中无论什么时候都只有一个 JS 线程在运行 JS 程序。
  • 注意,==GUI 渲染线程与 JS 引擎线程是互斥的==,所以如果 JS 执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞。

事件触发线程

  • 归属于浏览器而不是 JS 引擎,用来控制事件循环(可以理解,JS 引擎自己都忙不过来,需要浏览器另开线程协助)
  • 当 JS 引擎执行代码块如 setTimeOut 时(也可来自浏览器内核的其他线程,如鼠标点击、AJAX 异步请求等),会将对应任务添加到事件线程中
  • 当对应的事件符合触发条件被触发时,该线程会把事件添加到待处理队列的队尾,等待 JS 引擎的处理
  • 注意,由于 JS 的单线程关系,所以这些待处理队列中的事件都得排队等待 JS 引擎处理(当 JS 引擎空闲时才会去执行)

定时触发器线程

  • 传说中的 setInterval 与 setTimeout 所在线程
  • 浏览器定时计数器并不是由 JavaScript 引擎计数的,(因为 JavaScript 引擎是单线程的, 如果处于阻塞线程状态就会影响记计时的准确)
  • 因此通过单独线程来计时并触发定时(计时完毕后,添加到事件队列中,等待 JS 引擎空闲后执行)
  • 注意,W3C 在 HTML 标准中规定,规定要求 setTimeout 中低于 4ms 的时间间隔算为 4ms。

异步 http 请求线程

  • 在 XMLHttpRequest 在连接后是通过浏览器新开一个线程请求。
  • 将检测到状态变更时,如果设置有回调函数,异步线程就产生状态变更事件,将这个回调再放入事件队列中。再由 JavaScript 引擎执行。

题目

1. 为什么 Javascript 要是单线程的 ?

  • 如果 JavaScript 是多线程的方式来操作这些 UI DOM,则可能出现 UI 操作的冲突。
  • 如果 Javascript 是多线程的话,在多线程的交互下,处于 UI 中的 DOM 节点就可能成为一个临界资源,
  • 假设存在两个线程同时操作一个 DOM,一个负责修改一个负责删除,那么这个时候就需要浏览器来裁决如何生效哪个线程的执行结果。
  • 当然我们可以通过锁来解决上面的问题。但为了避免因为引入了锁而带来更大的复杂性,Javascript 在最初就选择了单线程执行。

2. 为什么 JS 阻塞页面加载 ?

  • 由于 JavaScript 是可操纵 DOM 的,如果在修改这些元素属性同时渲染界面(即 JavaScript 线程和 UI 线程同时运行),那么渲染线程前后获得的元素数据就可能不一致了。
  • 因此为了防止渲染出现不可预期的结果,浏览器设置 GUI 渲染线程与 JavaScript 引擎为互斥的关系。

3. css 加载会造成阻塞吗 ?

  • CSS 加载不会阻塞 DOM 的解析,会阻塞 Dom 的渲染

DOM 和 CSSOM 通常是并行构建的,所以 CSS 加载不会阻塞 DOM 的解析。

然而,由于 渲染树 是依赖于 DOM树 和 CSSOM树 的,
所以他必须等待到 CSSOM树 构建完成,也就是 CSS 资源加载完成(或者 CSS 资源加载失败)后,才能开始渲染。
因此,CSS 加载会阻塞 Dom 的渲染。

  • css 会阻塞后面 js 的执行。

由于 GUI 渲染线程与 JavaScript 引擎为互斥的关系。因此,样式表会在后面的 js 执行前先加载执行完毕,所以css 会阻塞后面 js 的执行。

4. DOMContentLoaded 与 load 的区别 ?

  • 当 DOMContentLoaded 事件触发时,仅当 DOM 解析完成后,不包括样式表,图片。
  • 当文档中没有脚本时,浏览器解析完文档便能触发 DOMContentLoaded 事件。如果文档中包含脚本,则脚本会阻塞文档的解析,而脚本需要等 CSSOM 构建完成才能执行。在任何情况下,DOMContentLoaded 的触发不需要等待图片等其他资源加载完成。
  • 当 onload 事件触发时,页面上所有的 DOM,样式表,脚本,图片等资源已经加载完毕。
  • DOMContentLoaded -> load

5. defer 和 async 的区别 ?

-------------本文结束 感谢您的阅读-------------