本文不是去剖析浏览器的底层原理或者具体的前端优化细节,而主要是讲述浏览器是如何对页面进行渲染的,即浏览器的渲染原理。

前端相关的技术,日新月异,更新迭代的速度非常快,只有掌握了渲染原理,才能更好的设计优化方案,因为本来前端的各种预编译、预加载、按需加载、资源合并等优化方案,都是针对浏览器的渲染来进行优化的,最终的目的就是呈现好的效果给用户,给用户一个好的使用体验。

有些浏览器最上方没有地址栏(原创)(1)

Chrome

说到浏览器的页面渲染,有几个不得不提到的相关概念。

关键渲染路径:是指与当前用户的操作有关的内容。说白了就是浏览器呈现给用户的页面,具体内在的浏览器接收的 HTML / CSS / JavaScript 之类的可以不管先,知道是用户所看到的页面即可。

渐进式渲染:是指用尽可能快的速度呈现给用户页面内容的技术。举个简单的例子就很容易理解这句话了,jpeg文件有两种保存方式,分别是标准型与渐进式,标准型是从上到下的扫描,内容相当于是一行一行的展现出来的(网速慢的时候可以看出很明显的效果),而渐进式是多次扫描,先显示图片轮廓,接着每次扫描的精度逐渐提高,呈现的内容越来越清晰,直至加载完成。

有些浏览器最上方没有地址栏(原创)(2)

Key

渲染过程

我们从几个大方面看,在地址栏输入地址后,看看都干了些什么:

  1. DNS服务器解析URL中域名所对应的IP
  2. 解析IP,与服务器建立TCP连接
  3. 浏览器发起HTTP请求/响应
  4. 服务器响应所请求的内容
  5. 客户端即浏览器对内容进行渲染

这里我想说说的是第5部分的内容,也就是浏览器是如何对内容进行渲染的。而这一过程,又可以更加具体的细分:

如上的几个具体细节,并不是一次性按顺序完成的,而是不断重复的过程,解析 - 构建 - 布局 - 绘制 - 重绘,不断的计算哪些内容需要渲染,进而在屏幕上呈现。

有些浏览器最上方没有地址栏(原创)(3)

Paint

阻塞资源

DOM(Document Object Model)树的构建过程,是一个深度遍历的过程,只有在当前节点的所有子节点都构建完成后,当前节点才会继续构建下一个兄弟节点。另外,DOM Tree 的根节点就是 Document 。

CSS 被视为渲染阻塞资源,即在 CSSOM Tree 构建完成前,浏览器不会对任何已经处理的内容进行渲染。JavaScript 不仅可以读取和修改 DOM 属性,同时还可以读取和修改 CSSOM 属性,所以存在阻塞的 CSS 资源时,JavaScript 会被延迟执行,DOM 构建也将延迟。

JavaScript 被视为解释器阻塞资源,HTML 的解析会被 JavaScript 阻塞。另外需要注意的是 document.createElement 创建的 script 标签时 async 的属性值。

综合上述两点,很显然说的是 HTML 解析器在构建 DOM 过程时:

当遇到 script 标签时,DOM 构建延迟,直至 JavaScript 脚本执行完成。

CSSOM 构建时,JavaScript 脚本执行将延迟,直至 CSSOM 构建完成。

知道了上述两点,也就很容易的能总结出前端项目优化的一些规则:

CSS 优先,先于 JavaScript 资源

JavaScript 尽量少影响 DOM 构建

有些浏览器最上方没有地址栏(原创)(4)

JavaScript

阻塞模式

script 标签有两个属性,分别为 defer 和 async,即延迟加载脚本和异步加载脚本,能改变上述所说的阻塞情况,但这两个属性对于内联脚本标签无效,针对的是带了 src 属性的 script 标签,如下所示:

// 从上直下顺序执行,defer / async 属性无效 <script defer> console.log('https://blog.makeit.vip'); </script> <script async> console.log('https://account.makeit.vip') </script>

defer 属性,表示的是延迟加载执行,按序执行,即在 HTML 解析过程中,不会阻塞 DOM 构建,直至解析完成后,按顺序进行加载执行。

// DOM 构建完成,然后按顺序加载 JavaScript 脚本 <script src="makeit-blog.js" defer></script> <script src="makeit-account.js" defer></script>

async 属性,表示的是异步加载执行,JavaScript 脚本加载期间,不影响 HTML 解析,但是一旦加载完成,将暂停 DOM 构建,进而先执行 JavaScript 脚本内容,即使 DOM 构建完成,处于 DOMContentLoaded 状态,异步脚本加载完成后就立马执行,但一定要在 Load 状态之前执行。执行并无先后顺序,谁先加载完成就先执行谁。

上面说到 document.createElement 创建 script 标签,需要注意的就是 async 属性默认是为 true 的,若是不希望如此的话,就需要手动修改该属性值了。

总结

就先记录这么多吧,主要记住以下几点:

  1. CSS 资源阻塞渲染,没构建完成前,浏览器是不会渲染任何内容的。
  2. JS 阻塞 HTML 解析
  3. CSS 资源优先加载
  4. defer 与 async,延迟与异步加载脚本
,