第1页.png
2020-12-21补充:《深入理解现代浏览器》对本文有直接指导。

通过之前的解释,我们已经(大概)知道了一个web请求发出去会经历怎样的心路历程。

在本篇会尝试解释浏览器收到了返回数据(特指html结构),大概会发生什么。也就是:浏览器如何工作,怎么渲染页。

前置知识

说尽网页导航Navigation

  • browser process
    • ui thread
    • network thread
  • renderer process
    • main thread
    • worker thread
    • compositor thread
    • raster thread

核心思路

这里都是 renderer process 里的 main thread 做的:

  • Parse HTML :构建DOM 树。把字符串照规则 token 词法分析变成node节点,然后变成 dom树。Document Object Model
  • subresource loading加载子资源,先扫描一遍
    • js can block the parsing遇到script标签,会停止解析HTML,下载、解析、执行,会阻塞DOM树生成。当然了这里有 defer/async 也有preload
  • 计算样式 parse stylesheet,并行构建CSSOM 树: css Object Model Tree 并标准化,也就是比如rem em转为px,white red转成rgb,不写样式也有默认样式
  • 布局Layout,把DOM树和CSSOM树合成一个 Layout Tree ,这里不包含 none 的元素,添加伪元素
  • Update Layer Tree
  • 绘制Paint,确定顺序paint record,比如z轴的互相遮盖。
  • 先分层再栅格化。合成线程把layer分成tiles块,交给栅格线程raster thread——栅格化块——存到GPU的内存里
  • 合成compositing,合成线程compositor thread 收集要绘制的块信息draw quads,创建合成帧compositor frame。
  • 合成帧通过gpu绘制到屏幕上。

Composite Layers

这里注意 dom tree 和 CSSOM Tree 是并行的,因此我们建议把css放到head里,尽可能早解析

细枝末节

1 页面为何白屏

浏览器的js引擎和渲染引擎都可以操作DOM,会造成资源的竞争,因此某一时刻只有一个线程操作DOM,也就是js引擎和渲染引擎会相互阻塞。

如果script里的js耗时长,会阻塞页面渲染。也就是会导致页面白屏。因此一般

  • 把js放页面底部,
  • async/defer 延迟执行js 都会立即下载
    • async并发获取js,得到之后立即执行,无需考虑顺序。但执行js依然会阻塞。动态创建script默认是async=true
    • defer延迟js执行,等到HTML文档解析之后,在DOMContentLoaded之前,再执行
  • 有些耗时js可以放到sw里执行

先保证页面渲染,不受js引擎阻塞。

2 Layout 和 Paint 关系

如何从技术上看到 绘制Paint和布局Layout的关系?

我们书写一个html,里面有1000个tag标签,写一点简单的样式。通过 devTools 里的 Performance - Bootom-Up 可以看到下面的图片:

image.png

可以看到,Layout耗时8.3ms,Paint耗时0.5ms

有了这个基础数据,我们通过js修改样式,修改margin值,这显然会重新计算布局,也就是 ReLayout

image.png

这个是先渲染,然后执行js得到的结果。我们可以看到 Layout耗时增加, Paint耗时增加。

接下来我们渲染完之后操作js修改字体颜色,得到下面的结果。可以看到 Layout几乎没有增加,这意味着RePaint机会不会影响Layout
image.png

但如果修改了字体,一样会触发ReLayout ,简单的结论是:

  • 减少Layout操作
  • Paint操作不一定会引起Layout

重排 reflow 也就是 re-layout
DOM中每个元素都有自己的盒子模型,需要浏览器根据样式来计算,放到该出现的位置,这个过程叫 reflow

  • 增加删除修改 DOM节点,会导致reflow repaint
  • 移动DOM的位置,或做动画
  • 修改css样式
  • resize窗口时候,或滚动时候
  • 修改默认字体时候

重绘 repaint
等到各种盒子位置等属性确定之后,浏览器把元素绘制页面

  • DOM 改动
  • CSS改动

资源外链

css 资源

  • css下载异步,不会阻塞构建DOM树
  • 会阻塞渲染,构建render的时候会等到下载解析完毕后进行。
  • 媒体查询不会阻塞渲染

js资源

  • 阻塞浏览器的解析,等待js下载解析并执行后继续解析html
  • defer和async,前者是延迟执行,后者是异步执行。
  • async是异步执行,异步下载结束后就能执行,不保证执行顺序
  • defer是延迟执行,效果看起来像放到body后面一样。

img

图片异步下载,不阻塞

loaded 和 domcontentloaded

  • load 事件触发时候,页面上的DOM ,css,js,img都加载完了
  • DOMContentLoaded 仅当DOM加载完成,不包括css,图片。

下一节: js运行机制