浏览器渲染页面的过程
- 当网页被下载下来后,开始解析html文档,把需要用到的资源进行下载
- 当遇到script时,会同步下载,并执行完script中的代码后,开始下载之后的资源,js会阻断domtree的构建。当同步的js全部执行完,domtree构建完后,DOMContentLoaded才会被触发。
- 当遇到样式link时,会异步下载,不会影响其他文件的下载,但在加载结束前,会阻断其后面js的执行。css不会直接影响domtree的构建,但是会影响页面的渲染。css加载结束之前,浏览器不会将其后面的元素渲染到页面
- 除了script和css以外,其余的资源如图片等,都属于异步加载,并对其他元素没有任何影响,当所有资源加载完毕后,会触发onload事件。
window.onload
- window.onload要等到页面解析完成,包括dom tree构建、cssom构建、render tree构建完毕,页面渲染完毕,页面中所需的资源全部加载完毕后,开始执行。
<body>
<div>0</div>
<script type="text/javascript">
document.write(1);
</script>
</body>
页面呈现 0 和 1
原因:<script>属于dom tree的一部分,在构建dom tree未构建结束时,
会将document.write输出的元素追加到已有元素的后面。
<div>0</div>
<script type="text/javascript">
window.onload = function () {
document.write(1)
}
</script>
页面呈现 1
window.onload是在页面全部加载完毕后执行,此时document.write相当于是在覆盖整个dom tree
页面渲染的过程
老浏览器,http请求回来页面后:
1.构建dom tree。(html中所有的标签都属于domtree里的元素)
2.遇到link或style,单独开启线程,异步加载样式,并构建cssom。
3.dom tree和cssom构建完毕后,形成render tree,然后开始渲染页面。
4.构建dom tree的过程中,遇到同步script则同步加载并执行script,script会参与dom tree的构建(如document.write不会覆盖页面) 。script执行结束后,继续往后构建dom tree。
5.构建dom tree的过程中,遇到图片、iframe资源会异步加载资源,不影响domtree、rendertree的构建及渲染。
现代浏览器,http请求回来页面后:
1.构建dom tree,并渲染已构建部分。
2.遇到link或style,单独开启线程,异步加载样式,并解析成cssom。cssom构建后,开始渲染已构建的domtree。
3.构建dom tree的过程中,遇到script则同步加载并执行script。script执行结束后,继续往后解析、渲染剩余部分。
4.遇到图片、iframe资源会异步加载资源,不影响render tree的渲染。但是css会影响其后面rendertree以及script的执行。
时间线
什么是时间线?
- 从页面开始加载到页面全部加载完毕的这个过程,发生的每一件事的流程叫做时间线。
时间线
- 页面开始加载时,浏览器会先创建一个document对象,此时JS功能体就生效了(生成document对象就是JS行为)。
- 解析文档
- 解析文档的定义:浏览器会把html文档从第一行阅读到最后一行
- 解析文档的过程中会构建domtree
- 解析的过程中遇到link会异步加载css外部文件,构建domtree的同时,会根据style或css文件构建cssom。
- 如果遇到同步的script(一般默认都是同步的script,除非手动设置),会阻塞文档的解析,之前异步进行的cssom构建也会停止。直到script加载并执行完毕后,才会继续解析文档。
- 如果遇到异步的async script,异步加载js脚本并且执行,加载时不阻塞文档的解析。当加载结束后,会等当前正在运行的同步<script></script>执行结束后,开始执行。而不是等所有的同步<script></script>执行完后才执行。
- 使用async="async"、async="async"可以让脚本变异步(defer和async只能用其中的一个)。
- 特殊:如果使用defer="defer"属性,异步脚本会等文档解析结束后,才运行。
- 异步脚本中无法使用document.write(),会静默失败。
- 但如果在异步脚本的window.onload中使用document.write是可以重写整个文档。
- 遇到图片资源,首先会解析img这个节点,然后异步加载src里的图片资源,加载的过程不阻塞文档解析。
- 文档解析完成。
- 文档解析完成后,已加载完的defer script会按顺序开始执行。加载中的异步脚本(async和defer),不会阻塞defer脚本的执行。
- 文档解析完成后,会触发DOMContentLoaded事件,此时代表domtree构建完毕。但不代表所有的资源加载完成。
- 此时程序由同步的脚本执行阶段进入事件驱动阶段。事件驱动阶段,代表用户可以和页面开始进行交互行为,如点击、输入等操作。
- 当异步脚本、css文件、图片等资源加载并执行结束后,最后会触发window的onload事件。(ajax请求属于js执行范畴,和时间线没有关系。ajax的回调运行在哪个环节,要看网络的快慢,有可能在onload之前,也可能在其之后。)
extends
- 生命周期状态
- document.readyState代表网页被执行的状态
- 通过document.onreadystatechange可以监听生命周期状态的变化
- 通过DOMContentLoaded可以监听domtree是否构建完毕
- loading 代表domtree并render中;
- interactive代表domtree构建完毕并进入可交互状态
- complete代表页面全部加载完毕
<script type="text/javascript">
console.log(document.readyState); // loading
document.onreadystatechange = function () { // 会被执行两遍
console.log(document.readyState);
// domtree构建完为interactive;
// 页面全部加载完为complete;
}
document.addEventListener('DOMContentLoaded', function () {
console.log('loaded'); // 会和iteractive一起打印 他两代表同一个阶段
})
</script>
-
window.onload和document.addEventListener('DOMContentLoaded')的区别
- 前者要等所有资源全部加载完进行回调执行,后者当页面解析完(即domtree构建完)进行回调执行。
- DOMContentLoaded等同于Jquery中的$(document).ready(function(){})、$(function(){})、$(document).on('ready', function(){})任意一种
-
DOMContentLoaded存在兼容性问题,以下为兼容代码
-
document.write
- 以一个script为单位,同一script中的document.write会进行合并后一起渲染到页面。
- 因此比较耗时的程序都会阻断当前脚本的docment.write。
- 异步脚本中的document.write会静默失败。
- alert会阻断所有脚本中的document.write,即使不在同一个script中,alert也会阻断之前script中的document.write。
-
alert
- 会阻断页面的渲染
- 阻断程序的执行
- 阻断document.write
async script使用场景
- 不会影响到其他模块的时候,可以使用async script。例如一些工具类,就不可以使用async。因为会被其他模块所依赖。但比如一些统计类的代码即可用到async script。
疑问
1.script文件,属于同步加载,为什么会在执行前面的代码时,后面的script文件就出现在了network里,但是没有开始下载?
- 猜测:原因是浏览器首先会全部解析一遍文档,解析的过程中,会构建domtree、运行script。同时会继续解析后面的文档,寻找需要下载的资源,等待script运行结束后,开始下载。
- 图片资源加载时,是一遍下载一遍渲染?而不是等全部加载结束后才渲染。
图片未给宽高,加载后是否会回流?
- 测试后答案:一边下载一边渲染。不会造成回流,开始下载的那一刻就知道了宽高。
- css文件属于异步加载,加载结束后,会导致页面回流或重绘?
- 如果是对已渲染的元素产生影响,有可能会回流或重绘。但对css后面的元素不会造成影响。因为后面的元素只是形成了domtree,还未生成rendertree。
网友评论