sunilwang

V1

2022/11/07阅读:19主题:橙心

浅谈浏览器的渲染原理

前言

对于一个前端来说,每天打交道最多的就是浏览器。从刀耕火种时代的ie浏览器,到代表现代先进的chrome浏览器,浏览器的整个架构发生了翻天覆地的变化。了解浏览器,不仅可以帮助我们更好地理解前端工作,还会为我们在技术优化的层面上提供更多的角度。

了解进程与线程

在介绍浏览器之前,我们先了解进程与线程概念。 进程是操作系统资源分配的基本单位,进程中包含线程。例如启动一个程序,就开启了一个进程。 线程有时候进程不止要干一件事,要同时干多件,就需要同时运行多个子任务,把这些子任务称之为线程,为了提升浏览器的稳定性和安全性,浏览器采用了多进程模型。

可以将进程和线程类比成工厂和工人,例如:

  • 进程是一个工厂,工厂有它的独立资源
  • 工厂之间相互独立
  • 线程是工厂中的工人,多个工人协作完成任务
  • 工厂内有一个或多个工人
  • 工人之间共享空间

再完善两者之间的概念:

  • 工厂的资源 -> 系统分配的内存(独立的一块内存)
  • 工厂之间的相互独立 -> 进程之间相互独立
  • 多个工人协作完成任务 -> 多个线程在进程中协作完成任务
  • 工厂内有一个或多个工人 -> 一个进程由一个或多个线程组成
  • 工人之间共享空间 -> 同一进程下的各个线程之间共享程序的内存空间(包括代码段、数据集、堆等)

浏览器是多进程的

理解了进程与线程了区别后,接下来对浏览器进行一定程度上的认识:(先看下简化理解)

  • 浏览器是多进程的
  • 浏览器之所以能够运行,是因为系统给它的进程分配了资源(cpu、内存)
  • 简单点理解,每打开一个Tab页,就相当于创建了一个独立的浏览器进程。
image.png
image.png

图中打开了Chrome浏览器的多个标签页,然后可以在Chrome的任务管理器中看到有多个进程(分别是每一个Tab页面有一个独立的进程,以及一个主进程)。 如果再多打开一个Tab页,进程正常会+1。

浏览器都包含哪些进程

知道了浏览器是多进程后,再来看看它到底包含哪些进程

image.png
image.png
  • Browser进程:浏览器的主进程(负责协调、主控),只有一个。
    • 负责浏览器界面显示,与用户交互。如前进,后退等
    • 负责各个页面的管理,创建和销毁其他进程
    • 将Renderer进程得到的内存中的Bitmap,绘制到用户界面上
    • 网络资源的管理,下载等
  • 插件进程:每种类型的插件对应一个进程,仅当使用该插件时才创建
  • GPU进程:最多一个,用于3D绘制等
  • 渲染进程(浏览器内核):默认每个Tab页面一个进程,互不影响。主要作用是页面渲染,脚本执行,事件处理等
  • 网络进程:处理网络资源

浏览器多进程的优势

相比于单进程浏览器,多进程有如下优点:

  • 由于默认 新开 一个 tab 页面 新建 一个进程,所以单个 tab 页面崩溃不会影响到整个浏览器。
  • 第三方插件崩溃也不会影响到整个浏览器。
  • 多进程可以充分利用CPU多核的优势。
  • 方便使用沙盒模型隔离插件等进程,提高浏览器的稳定性。

缺点就是系统为浏览器新开的进程分配内存、CPU 等资源,所以内存和 CPU 的资源消耗也会更大,相当于用空间换时间了。

重点是浏览器内核(渲染进程)

上面提到了这么多的进程,那么,对于前端来说,最终要的是什么呢?答案是渲染进程

GUI渲染线程

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

JS引擎线程

  • 也称为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引擎执行。

GUI渲染线程与JS引擎线程是互斥的 由于JavaScript是可操纵DOM的,如果在修改这些元素属性同时渲染界面(即JS线程和UI线程同时运行),那么渲染线程前后获得的元素数据就可能不一致了。 因此为了防止渲染出现不可预期的结果,浏览器设置GUI渲染线程与JS引擎为互斥的关系,当JS引擎执行时GUI线程会被挂起, GUI更新则会被保存在一个队列中等到JS引擎线程空闲时立即被执行。

浏览器渲染流程

在介绍浏览器渲染过程之前,先介绍下页面的加载过程,有助于更好理解后续渲染过程。

1.浏览器根据 DNS 服务器得到域名的 IP 地址 2.向这个 IP 的机器发送 HTTP 请求(http请求阶段) 3.服务器收到、处理并返回 HTTP 请求(http响应阶段) 4.浏览器得到返回内容(浏览器渲染阶段)

浏览器器内核拿到内容后,渲染大概可以划分成以下几个步骤:

  1. 构建dom树
    • 浏览器无法直接使用 HTML,要先解析HTML生成DOM树
    • DOM树的构建过程:字节 -> 字符 -> 标记(token)-> DOM节点对象 -> DOM对象模型
  2. 构建样式树
    • 浏览器无法解析纯文本的 CSS 样式,需要对 CSS 进行解析,生成CSSOM树。
    • CSSOM树的构建过程:字节 -> 字符 -> 标记(token) -> CSS节点对象 -> CSS对象模型
    • 计算出 DOM 树中每个节点的具体样式(Attachment)(打开浏览器Elements标签,查看元素格式化好的样式)
  3. 创建渲染树
    • 将DOM树和CSSOM树这两个对象集合结合一起,形成渲染树
  4. 布局
    • 从render树的根节点开始遍历,计算节点渲染到页面的坐标位置。(reflow回流)
  5. 绘制
    • 根据渲染树以及回流得到的几何信息,得到节点的绝对像素。(Painting 重绘)
  6. 分层
    • 通过以下几个常用属性可以生成新图层
      • 3D 变换:translate3d、translateZ;
      • video、iframe 标签;
    • 通过动画实现的 opacity 动画转换;
    • position: fixed;
  7. 显示
    • 浏览器会将各层的信息发送给GPU,GPU会将各层合成,将内容显示在页面上。

渲染完毕后就是load事件了,之后就是自己的JS逻辑处理了。

输入url到整个页面发生了什么

最后我们来看一个经典问题,输入url到整个页面发生了什么?

  1. 用户输入url,浏览器进程开始处理
    • 如果是关键词,会使用默认搜索引擎合成带有搜索关键字的URL;
    • 如果是URL,或者是符合url规则的的内容,会带上协议合成完整的URL。
  2. URL请求过程:
    1. 网络进程先对本地进行判断是否有缓存,有的话直接将资源返回给浏览器进程,没有的话进行下一步。
    2. DNS通过域名解析得到IP地址。
    3. 将IP地址和服务器TCP连接,三次握手。
    4. 服务器收到请求的信息后,会根据请求的信息生成响应头,响应行,响应体,然后发送给网络进程,网络进程接受了响应的信息后,就开始解析响应头的内容。
    5. 解析的过程:有可能进行重定向(状态码301,302时),重新发起请求。
    6. 浏览器通过请求头的Content-type字段判断如何显示响应体的内容,比如是text/html,返回的是html格式,浏览器通知渲染进程,要开始干活了。
  3. 渲染进程开始准备
  4. 提交文档
    1. 渲染进程准备好后,浏览器进程发出提交文档的消息
    2. 渲染进程接收消息
    3. 跟网络进程建立传输数据的通道
    4. 数据传输完成后,渲染进程会告诉浏览器进程,确认文档提交,浏览器更新页面。
作者简介

王胜开:管住嘴,迈开腿,准备减肥

分类:

前端

标签:

计算机网络

作者介绍

sunilwang
V1