前端 浏览器页面渲染的过程

    最近遇到了这么一个问题,关于HTML页面的加载渲染的顺序,在chorme浏览器控制台的timeline测试许久,结合网上的资料,终于理出了个头绪。其中有两个博主写的很好,以下段落中也进行了参考和摘抄。

浏览器加载、解析、渲染的过程 - 季诗筱的博客 - 博客频道 - CSDN.NET
http://blog.csdn.net/xiaozhuxmen/article/details/52014901

了解html页面的渲染过程 - yuezk - 博客园
http://www.cnblogs.com/yuezk/archive/2013/01/11/2855698.html

正文

一、相关知识点

  1. 当浏览器获得一个html文件时,会“自上而下”加载。

  2. 浏览器会将HTML解析成一个DOM树,构建过程是深度遍历:当前节点的所有子节点都构建好后才会去构建当前节点的下一个兄弟节点。

  3. 浏览器将CSS解析成 CSS Rule Tree 。

  4. 根据DOM树和CSSOM(CSS Object Model)来构造 Rendering Tree。

  5. 有了 Rendering Tree才会进行Layout(计算出每个节点在屏幕中的位置)和painting,不是仅仅有了dom树就可以显示的。

  6. js脚本,主要是通过 DOM API 和 CSSOM API 来操作 DOM Tree 和 CSS Rule Tree.

二、流程

  1. 浏览器向服务器发出请求,服务器返回html文件,浏览器开始载入html代码并解析。
  2. <head>标签内有一个<link>标签引用外部CSS文件,下载CSS文件。但解析器没有阻塞,HTML依然继续解析但是不会显示,因为没有CSS还没到手呢。
  3. 如果CSS是嵌入式的,没关系,只是不用去下载了。CSS拿到手,为了更好的用户体验,渲染引擎将会尽可能早的将内容呈现到屏幕上,并不会等到所有的 html都解析完成之后再去构建和布局render树。它是解析完一部分内容就显示一部分内容,同时,可能还在通过网络下载其余内容。
  4. 接下来遇到了script标签,如果是外部文件,好了,添加到下载的队列中。由于script是必须立刻执行的,所以下载完之前,解析器也阻塞了。如果是嵌入式的就会立刻执行。
  5. 接下来在代码中发现一个<img>标签引用了一张图片,向服务器发出请求。此时浏览器不会等到图片下载完,而是继续渲染后面的代码。 等下载完图片文件后,由于图片占用了一定面积,影响了后面段落的排布,因此浏览器需要回过头来重新渲染这部分代码;
  6. 别忘了,后面也许还会有CSS内联代码和js内联代码。orz,这时候又回重新来过。当然也有轻重之分:如果影响了布局浏览器就需要回去重新渲染,这叫做reflow;如果不影响布局只是改变了某个元素的背景颜色,文字颜色等,将只会引起浏览器的repaint,重画某一部分。

三、分析

  1. script的js代码都是立刻执行的,如果将script标签放在head中,dom有可能带没解析出来会产生一定的错误。

    • 解决办法1:将标签放在body标签里的最后的位置。
    • 解决办法2:script有两个属性,defer和async。设置defer="defer",脚本会被延迟到整个页面都解析完毕后(遇到)再运行,如果有多个脚本的话,H5规定顺序执行。但实际中不一定顺序执行,不同的浏览器支持程度也不同。设置async,效果和defer一样,只是他是肯定不支持顺序执行多个脚本的。另外defer和async都只是用于外部脚本。所以还是解决办法1更为稳妥。
    • 解决办法3:使用动态创建的script元素来下载并执行代码;
    • 解决办法4:onload、ready 区别见链接 http://www.cnblogs.com/cuncunjun/p/6531960.html
    • 注意:尽可能地合并脚本。页面中的script标签越少,加载也就越快,响应也越迅速。无论是外链脚本还是内嵌脚本都是如此。
  2. 关于渲染过程是解析完一部分就显示一部分。如果遇到解析器阻塞,等待下载其他文件的话,这是浏览器会收到绘制的请求,这时候会显示一部分。如果期间一直没有阻塞,究竟怎么样算一部分,怎么一点点绘制显示还有待研究,还请诸位大神赐教。

  3. 编写CSS时应该注意:
        CSS选择符是从右到左进行匹配的。从右到左!所以,.class li 我们以为x先找到所有的类名为class的然后li。但其实,浏览器会去找所有的li,然后再去确定它的父元素是不是.class,因此,写css的时候需要注意:

    • dom深度尽量浅。
    • 减少inline javascript、css的数量。
    • 使用现代合法的css属性。
    • 不要为id选择器指定类名或是标签,因为id可以唯一确定一个元素。
    • 避免后代选择符,尽量使用子选择符。原因:子元素匹配符的概率要大于后代元素匹配符。后代选择符;#tp p{} 子选择符:#tp>p{}
    • 避免使用通配符,举一个例子,.mod .hd *{font-size:14px;} 根据匹配顺序,将首先匹配通配符,也就是说先匹配出通配符,然后匹配.hd(就是要对dom树上的所有节点进行遍历他的父级元素),然后匹配.mod,这样的性能耗费可想而知.
原文地址:https://www.cnblogs.com/cuncunjun/p/6531495.html