有了这个标准,运行JavaScript就能给我们一致的体验,无论是在浏览器中,还是Node.js中,Deno等环境中运行相同的JS代码,都能给我们相同的结果。。这很棒,并且会提高我们的产品质量。
然而,这种情况在浏览器渲染中就不存在了,尽管HTML,CSS,JavaScript,这些语言的标准被一些机构控制,但浏览器把它们组合到一起,如何渲染出来,这个过程没有标准化。各个公司就各个公司的办法。比如Chrome就跟Safari的做法不一样。
因此很难预测在一个特殊浏览器中的渲染顺序和机制。尽管如此,HTML规范也做了些努力来标准化渲染操作。但是浏览器怎么遵守,遵守多少完全取决于他们自己。
除了这些不一致性,有些共通的东西是在所有浏览器中是一样的。 让我们来理解一下通常浏览器渲染事件的过程是怎么样的。
解析和外部资源
解析是读取HTML构造DOM树的过程。所以这个过程也叫DOM解析,做这个工作的程序叫DOM Parser。
大多数浏览器提供了DOMParser API来构造一个DOM树。你可以试着构造一个DOMParser的实例,然后使用parseFromString方法,看看可以构造出一个什么DOM树。
![](http://imgq8.q578.com/ef/0613/5bc00e95f41e692d.jpg)
当浏览器请求一个页面,服务器返回了HTML文本(Content-Type设成text/html), 浏览器可以在只接收到整个文档中的开始几行或几个字符就开始解析操作。所以浏览器可以增量地构造DOM树,一次一个节点地从头到尾解析。
![](http://imgq8.q578.com/ef/0613/96621f956b39f9e1.jpg)
在上面这个例子中,我们访问incremental.html文件,设置网速只有10kbps,这样它会花很长时间来下载这个包含了1000个H1元素文件。从下图可以看到,浏览器从最初的收到的一些字节就开始构造DOM树,并把他们显示出来。剩下的东西还在后台下载中,就这样边下载边解析。
![](http://imgq8.q578.com/ef/0613/fe08806e05dbf910.jpg)
上面是该请求的性能图表, 你会看到这些事件发生的时间。当他们发生的越早,用时越短,说明用户体验越好。
FP表示首次渲染,表示浏览器开始在显示器上显示东西了。可能就是简单到显示Body中背景的第一个像素。
FCP表示首次内容渲染,说明浏览器已经渲染了图片或文字的第一个像素
LCP表示最大内容渲染,说明浏览器渲染了最大的一块文字或图片
L表示onload事件,是由浏览器的window对象发出的。类似的DCL由document对象发出,它冒泡至window,这样你就可以在window对象上监听它。这些事件有些复杂,我们接下来讨论它。
只要浏览器解析时碰到外部文件,它就会开始后台下载那个文件(非主线程)。比如JavaScript , CSS , image 或者其他任何外部资源都会这样。
最重要的就是要记住,解析通常发生在主线程。如果主线程解析JavaScript很忙,DOM解析操作就会停止工作,直到主线程再次空闲。之所以重要,因为只有