# 渲染机制

# DOCTYPE 作用

DTD(document type define,文档类型定义)是一系列的语法规则,用来定义 XML 或 (X)HTML 的文件类型。浏览器会使用它来判断文档类型,决定使用何种协议来解析,以及切换浏览器模式

DOCTYPE 是用来声明文档类型和 DTD 规范的,一个主要用途是文件的合法性校验,如果文件代码不合法,那么浏览器解析时便会报错

# 浏览器渲染过程

浏览器渲染过程

  1. 解析 HTML,生成 DOM 树(DOM)
  2. 解析 CSS,生成 CSSOM 树(CSSOM)
  3. 将 DOM 和 CSSOM 合并,生成渲染树(Render-Tree)
  4. 计算渲染树的布局(Layout)
  5. 将布局渲染到屏幕上(Paint)

# 关键概念

  • CSS 阻塞渲染:由于 CSSOM 负责存储渲染信息,浏览器就必须保证在合成渲染树之前,CSSOM 是完备(所有的 CSS,包括内联、内部和外部都已经下载完并解析完),只有 CSSOM 和 DOM 的解析完全结束,浏览器才会进入下一步渲染。CSS 阻塞渲染意味着,在 CSSOM 完备前,页面一直处于白屏状态,这就是为什么样式表放在 head 中,仅仅是为了更快的解析 CSS,保证更快的首次渲染

  • JS 阻塞页面:JS 可以操作 DOM 来修改 DOM 结构,可以操作 CSSOM 来修改节点样式,这就导致了常规情况下浏览器在解析 HTML 时,一旦碰到 script,就会立即停止 HTML 的解析,也阻塞了其后的 CSS 解析,整个解析进程必须等待 JS 的执行完成才能继续。从性能角度上讲,将 script 放在页面的底部

  • 重排(reflow):DOM 结构中的各个元素都有自己的盒子,这些都需要浏览器根据各种样式来计算并根据计算结果将元素放到它该出现的位置,这个过程称之为 reflow

    触发重排:

    • 当增加、删除、修改 DOM 节点时,会触发 reflow 或 repaint
    • 当移动 DOM 的位置,或插入动画的时候
    • 当修改 CSS 样式的时候
    • 当 resize 窗口或滚动的时候
    • 当修改网页的默认字体时
  • 重绘(repaint):当各种盒子的位置、大小以及其他属性,例如颜色、字体大小等都确定下来之后,浏览器便把这些元素都按照各自的特性绘制一遍,于是页面的内容出现了,这个过程称之为 repaint

    触发重绘:

    • DOM 改动
    • CSS 改动
  • 最小化重绘和重排:

    • 一次性修改样式:减少内联样式使用,样式合并写法
    • 批量修改 DOM:使用文档片段创建一个子树,然后再拷贝到文档中
    • 缓存布局信息

# 浏览器对 CSS 和 JS 的解析规则

# CSS

  • CSS 放在 head 中会阻塞页面渲染(页面渲染会等到 CSS 加载完成)
  • CSS 阻塞 JS 执行(因为 GUI 线程和 JS 线程互斥,因为 JS 有可能会操作 DOM)
  • CSS 不阻塞外部脚本的加载(不阻塞 JS 的加载,但阻塞 JS 的执行,因为浏览器会有预先扫描器)

# JS

  • 直接引入 JS 会阻塞页面的渲染(JS 线程和 GUI 线程互斥)
  • 异步加载的 JS(script 标签中添加 defer 属性)不阻塞页面的解析
  • 异步加载的 JS(script 标签中添加 async 属性)下载过程不阻塞页面的解析,下载完成后立即执行,执行过程会阻塞页面的解析
  • JS 不阻塞资源的加载
  • JS 顺序执行,阻塞后续 JS 逻辑的执行

# HTML 页面加载优化

# 页面减肥

页面的肥瘦是影响加载速度的最重要因素。删除不必要的空格、注释,将 inline 的 script 和 css 移到外部文件,可以使用 HTML Tidy 来给 HTML 减肥,还可以使用一些压缩工具来给 JS 减肥;

# 减少文件数量

减少页面上引用的文件数量可以减少 HTTP 连接数。许多 JS 、CSS 文件可以合并最好合并。

# 减少域名查询

DNS 查询和解析域名也是消耗时间的,所以要减少对外部 JS、CSS、图片等资源的引用,不同域名的使用越少越好。

# 缓存重用数据

# 优化页面元素的加载顺序

首先加载页面最初显示的内容和与之相关的 JS 和 CSS,然后加载 HTML 相关的东西,像不需要最初显示的如图片、视频等资源最后加载。

# 减少 inline js 的数量

浏览器解析起会假设 inline js 会改变页面结构,所以使用 inline js 开销比较大。不要使用 document.write() 这种输出内容的方法,使用现代 W3C DOM 方法来为现代浏览器处理页面内容。

# 使用现代 CSS 的合法标签

使用现代 CSS 来减少标签和图片,使用合法标签避免浏览器解析 HTML 时做 error correction。

# 不要使用嵌套 tables

# 指定 table 和图片的大小

如果浏览器可以立即决定图片或者表格的大小,那么它可以立马显示页面而不需要重新做布局安排,这不仅加快了页面的现实,也预防了页面完成加载后布局的一些不当改动。