当用户在浏览器输入一个地址后,浏览器最终会呈现一个完整的网页,会经历一下步骤。
1.加载并解析HTML
当用户输入url地址后,浏览器会先拿到html文件下载完并进行解析。
2.其他静态资源下载
html文件在解析过程中,如果发现html文本里,引入了一些外部资源链接,比如css、js和图片等,会立即启用别的线程下载这些静态资源。在<head> 标签中遇到js文件时,html的解析会被停下来,等js文件下载结束并执行完,html的解析才会继续,来防止js改变已解析的结果。
拓展
由以上可以知道,js文件放在<head>文件中,属于同步加载,会阻塞dom树的构建,进而影响页面的加载。当页面引入的js文件过多时,页面会出现长时间的白屏。 如何避免上面的问题呢?有以下三个解决方案。
1.<script>标签放在body标签里面(<body>之前)
由于dom是自上而下进行解析的,因此js不会阻塞dom的解析,而且这个时候可以在js中操作dom
2.设置defer属性
在<script>标签中设置defer属性,将脚本语言设置为延迟加载,当浏览器遇到带有defer属性的<script>标签时, 会再开启一个线程去下载js文件,同时继续解析html文件,等html全部解析完,dom加载完成后,再去加载下载好的js文件,只是用引入外部文件,并且可以确保所有加了 defer 属性的脚本会按顺序执行。
3.设置async属性
async属性和defer属性类似,也时开启一个线程去下载js文件,单核defer不同的是,async会在js文件加载完成后立即执行,而不是等到dom全部加载完成后再执行,所以还是有可能造成阻塞。同样的也是只是用外部引用脚本语言,如果有多个设置了async的文件,不能像defer那样按顺序执行。
4.动态创建脚本
<script>
var _html = _html || []
(function(){
var hm = document.createElement("script")
hm.src = "http://www.baidu.com/han.js"
var s = document.getElementsByTageName('script')[0]
s.parentNode.insertBefore(hm, s);
})()
</script>
3.dom树的构建
dom的全程,文档对象模型,在html解析时,解析器会把解析完的html转化成dom对象,再进一步的构建dom树
4.cssdom的构建
当css下载完成后,css解析器会对css进行解析,把css解析成css对象,然后把这些css对象组装成一颗cssdom树
5.渲染树的构成
dom和cssdom构建完成后,浏览器会根据这两颗树构建出渲染树
6.布局计算
渲染树构建完成以后,所有元素的位置关系和需要应用的样式就确定了。这时候浏览器会计算出所有元素的大小 和绝对位置
7.渲染
布局计算完成以后,浏览器就可以在页面上渲染元素了,经过渲染引擎的处理后,整个页面就显示在了屏幕上