1. 浏览器渲染的过程
最近一直想看看浏览器渲染以及前端性能优化的内容,可是在网上找到的都是文字描述,所以想通过网上的知识去对应到chrome performance看到的过程。
先看一个非常简单的页面代码(或者访问DOM-empty):
<!Doctye html>
<html>
<head>
</head>
<body>
<div>
Test dom load.
</div>
</body>
</html>
然后打开chrome performence查看页面的渲染过程:
Send Request 发送网络请求时触发
Receive Response 响应头报文到达时触发
Receive Data 请求的响应数据到达事件,如果响应数据很大(拆包),可能会多次触发该事件
Finish Loading 网络请求完毕事件
Parse HTML 浏览器执行HTML解析
Update Layer Tree (目前还没有找到具体的说明,后面会继续去查找,如果有了解的希望可以告知)。
Paint 确定渲染树上的节点的大小和位置后,便可以对节点进行涂鸦(paint)
Composite Layers 合成层;当渲染树上的节点涂鸦完毕后,便生成位图(bitmap),浏览器把此位图从CPU传输到GPU
2. Parse Html(without css and js)
今天主要是为了看一下Parse Html的过程,现在讲Parse Html的过程放大来看:
然后我们按照时间线从左到右来看一下里面的事情(先说一下,这个图怎么看,下面的内容是上面内容的调用,这里也就是上面带图中带有文字说明的内容都是在ParseHtml的周期内调用的内容):
readystatechange(第一个)
说这个的时候就需要说一个事件DOM readystatechange, readyState 属性描述了文档的加载状态,在整个加载过程中 document.readyState会不断变化,每次变化都会触发readystatechange事件。(可以访问查看例子)
readyState 有以下状态:
loading 加载document 仍在加载。
interactive 互动文档已经完成加载,文档已被解析,但是诸如图像,样式表和框架之类的子资源仍在加载。
complete 完成DOM文档和所有子资源已完成加载。状态表示 load 事件即将被触发。
那么这里的事件执行的是哪一步呢?
这里执行的是interactive。因为这个事件后面紧跟着的是 DOMContentLoaded事件,而且如果你亲自访问这个页面去看一下,在parseHtml前面还有一次readystatechange,那里应该是loading 。
DOMContentLoaded (构建 DOM 树成功)
DOM树渲染完成时触发DOMContentLoaded事件,此时可能外部资源还在加载。这里表示DOM树加载完成。
Recalculate Style(构建 CSSOM 树)
从文字的字面意义理解也就是重新计算样式。为什么是 Re-caculate Style 呢?这是因为浏览器本身有 User Agent StyleSheet,所以最终的样式是我们的样式代码样式与用户代理默认样式覆盖/重新计算得到的。这里也是在构建CSSOM树。
readystatechange(第二个)
从第一个事件的地方可有了解到这里执行的是complete,表示页面上的DOM树和CSSOM树已经形成并且合并成Render树。此时页面上所有的资源都已经加载完成。其实从后面的load事件也可以看出来。
load事件
所有的资源全部加载完成会触发window 的 load事件。
pageshow事件
当一条会话历史记录被执行的时候将会触发页面显示(pageshow)事件。(这包括了后退/前进按钮操作,同时也会在load事件触发后初始化页面时触发)。
以下示例将会在控制台打印由前进/后退按钮以及load事件触发后引起的pageshow事件:
window.addEventListener('pageshow', function(event) {
console.log('pageshow:');
console.log(event);
});
Layout
将渲染树上的节点,根据它的高度,宽度,位置,为节点生成盒子(layout)。为元素添加盒子模型。上图中有两个layout,二者之间的不同是Nodes That Need Layout 1/5 of 5
这里的5代表应该是页面上的5个node(文本内容是文本节点),但是对于这个1,还是没有一个明确的说明,但是影响不大,毕竟还是属于layout。
其实看到这里:我们想一下ParseHtml做了哪些内容:
构建DOM树 -> 构建CSSOM树 -> 构建Render树 -> 布局layout
Note: 这里执行的情况是这样的,但是当我们加上内部css和内部js的时候这个步骤就有了不一样的变化。
3. Parse Html(with css and js)
还是先把代码贴出来(可以访问DOM (with css and js)):
<!Doctye html>
<html>
<head>
<style type="text/css">
.div {
color: blue
}
</style>
</head>
<body>
<div class='div'>
Test dom load.
</div>
<script type="text/javascript">
var a = 1 + 1;
</script>
</body>
</html>
然后以同样的方式将chorme performence的过程贴出来:
这里就只说和上面图中不一样的地方:
首先是多个两个黄颜色的js相关的内容,一个叫做Evaluate Script(加载js),另一个是Compile Script(js预编译处理,可以查看文章,这里也已经对js文件执行了)。
第二个不同的地方是从第二个readystatechange事件起一直到layout都已经不在ParseHtml内部完成了。这里我简单的去做了一个测试,只有css或者js存在的情况下,还是和现在一样的结果,这里我假设是因为css或者js阻塞了整个页面的渲染过程,因为js和css都有可能对标签进行样式的设置,从而影响了layout的执行。当然这只是我的一个问题,后面我会带着这个问题继续学习!
那么现在ParseHtml就执行了:构建DOM树 -> 构建CSSOM树 -> 构建Render树。
写在最后:至于说DOM/CSSOM/Render树是如何的构建,在网上有很多的文章再说,更有How browsers work,可以进行学习。至于paint, Composite Layers其实和前端页面的渲染有着很大的关系,后面会有文章去学习。