今天看到了魔法哥以前的一篇文章,里面有提到一个经典的面试题:当我们输入网址后。。。 点击查看
由于文章的重点不是讲html页面渲染,于是我就动手写了这篇文章
js加载时间线与render树渲染过程的关系
思考?
render树生成的过程和js加载时间线的过程是怎样的一个联系?
render树是拿到html代码和css代码之后生成的吗?
js在什么时候才加载的?
在我们之前的文章里面,有提到过render树生成的过程。
浏览器拿到服务器传来的html代码,开始解析。
如果遇到了link引入一个css,就会异步加载这个css。 如果遇到了一个js,并且这个js没有显式声明为异步,就会去加载这个js,这个过程会阻止了css和dom的解析
解析dom树:根据html元素节点生成的一个dom树,如果这个元素节点浏览器不认识的话,是不会生成到dom树上面的(例如自己写一个<asdfa>这是我的元素节点</asdfa>
)。
解析cssom树(也有人称cssdom树):对于一些设置了不显示的样式,例如display:none,cssom树是不会渲染在上面的。
注意:dom树和cssom树是异步加载渲染节点的过程。即:浏览器解析出html代码里面引入了css文件,还会向服务器发起请求异步加载。
等到dom树和cssom树都生成好了,浏览器就会把这两棵树合并到一起,名字叫render树。
[为什么没有jsdom树?因为js是等浏览器把页面渲染完成之后(document.readyState='complete')才执行,js和render树结合到一起同时渲染是毫无必要的。]
render树建好了,就开始绘制到页面了。绘制过程还会遇到js、img等引用外部链接的元素,img是统一异步加载。js如果又是没有显式声明为异步(script没有defer、aysnc),那就单线程加载这个js,同时阻止了下面的渲染
js加载时间线
第一个阶段:render树生成阶段
- 创建document对象,开始解析web页面,解析html元素和他们的文本内容。添加element对象和text节点到文档中,这个阶段document.readyState=’loading’。逐步生成dom树
-
遇到link外部css,创建线程异步加载。继续解析下面的文件。逐步生成cssom树。
- 遇到img,就把img挂到dom树上面,同时异步加载img内容,继续解析下面的代码。
- 遇到script元素,忽略
- render树生成
第二个阶段:render树渲染
- 根据render树计算出样式并绘制页面
- 遇到script引入的js,如果没有显式声明aysnc(w3c标准、ie9以上)、defer(只有ie能用)属性,浏览器直接单线程加载,同时阻塞css以及html代码渲染到cssom树和dom树。这个时候,如果js操作了dom节点,恰巧这些节点没有生成,浏览器就会报错!!
(划重点:值得注意的是,render树生成前不会遇到js执行,遇到js也会无视掉。等第二次render树渲染过程遇到的js就会执行了,两者是不一样的。)
-
遇到script引入的js,如果显式声明aysnc(w3c标准、ie9以上)、defer(只有ie能用)属性,浏览器创建线程,继续解析下面的代码。但只有对于aysnc的js代码,加载完毕立即执行。
- 页面绘制完毕,此时document.readyState=’interactive’。刚才所有遇到的defer属性的js代码都会按顺序执行
-
没有defer或是defer执行完毕,这时候document对象就会触发DomContentLoaded事件,表示dom上下文加载完毕,可以触发事件了。这个阶段等同于jq中的
$(document)ready(function(){...})
。 - 这时候不能忘了刚才异步加载的js,我们怎样才能知道异步加载的资源全部都加载好了呢?其实,当所有资源加载完毕之后,readyState就会触发改变,即
document.readyState='complete'
,这个时候window就触发了load事件。 - 由此,js加载完毕