浏览器原理(二)

   

     下面是渲染引擎在取得内容之后的基本流程:

   

当浏览器获得一个html文件时,会“自上而下”加载,并在加载过程中进行解析渲染。 
 解析: 
        1. 浏览器会将HTML解析成一个DOM树,DOM 树的构建过程是一个深度遍历过程:当前节点的所有子节点都构建好后才会去构建当前节点的下一个兄弟节点。 
        2. 将CSS解析成 CSS Rule Tree 。 
        3. 根据DOM树和CSSOM来构造 Rendering Tree。注意:Rendering Tree 渲染树并不等同于 DOM 树,因为一些像 Header 或 display:none 的东西就没必要 放在渲染树中了。

        4.有了Render Tree,浏览器已经能知道网页中有哪些节点、各个节点的CSS定义以及他们的从属关系。下一步操作称之为Layout,顾名思义就是计算出每个节点在屏幕中的位置。 

        5.再下一步就是绘制,即遍历render树,并使用UI后端层绘制每个节点。

       上述这个过程是逐步完成的,为了更好的用户体验,渲染引擎将会尽可能早的将内容呈现到屏幕上,并不会等到所有的html都解析完成之后再去构建和布局render树。它是解析完一部分内容就显示一部分内容,同时,可能还在通过网络下载其余内容。

    几个概念: 
       (1)Reflow(回流):浏览器要花时间去渲染,当它发现了某个部分发生了变化影响了布局,那就需要倒回去重新渲染。 
       (2)Repaint(重绘):如果只是改变了某个元素的背景颜色,文字颜色等,不影响元素周围或内部布局的属性,将只会引起浏览器的repaint,重画某一部分。 
Reflow要比Repaint更花费时间,也就更影响性能。所以在写代码的时候,要尽量避免过多的Reflow。

   reflow的原因:

    (1)页面初始化的时候; 
    (2)操作DOM时; 
    (3)某些元素的尺寸变了; 
    (4)如果 CSS 的属性发生变化了。

    减少 reflow/repaint

        (1)不要一条一条地修改 DOM 的样式。与其这样,还不如预先定义好 css 的 class,然后修改 DOM 的 className。 
        (2)不要把 DOM 结点的属性值放在一个循环里当成循环里的变量。 
        (3)为动画的 HTML 元件使用 fixed 或 absoult 的 position,那么修改他们的 CSS 是不会 reflow 的。 
        (4)千万不要使用 table 布局。因为可能很小的一个小改动会造成整个 table 的重新布局。

    一个完整的HTML页面加载和解析流程如下:

            1. 用户输入网址(假设是个html页面,并且是第一次访问),浏览器向服务器发出请求,服务器返回html文件; 
            2. 浏览器开始载入html代码,发现<head>标签内有一个<link>标签引用外部CSS文件; 
            3. 浏览器又发出CSS文件的请求,服务器返回这个CSS文件; 
            4. 浏览器继续载入html中<body>部分的代码,并且CSS文件已经拿到手了,可以开始渲染页面了; 
            5. 浏览器在代码中发现一个<img>标签引用了一张图片,向服务器发出请求。此时浏览器不会等到图片下载完,而是继续渲染后面的代码; 
            6. 服务器返回图片文件,由于图片占用了一定面积,影响了后面段落的排布,因此浏览器需要回过头来重新渲染这部分代码; 
            7. 浏览器发现了一个包含一行Javascript代码的<script>标签,赶快运行它; 
            8. Javascript脚本执行了这条语句,它命令浏览器隐藏掉代码中的某个<div> (style.display=”none”)。突然少了这么一个元素,浏览器不得不重新渲染这部 分代码; 
            9. 终于等到了</html>的到来,浏览器泪流满面…… 
           10. 等等,还没完,用户点了一下界面中的“换肤”按钮,Javascript让浏览器换了一下<link>标签的CSS路径; 
           11. 浏览器召集了在座的各位<div><span><ul><li>们,“大伙儿收拾收拾行李,咱得重新来过……”,浏览器向服务器请求了新的CSS文件,重新渲染页面。

      编写CSS时应该注意:

      CSS选择符是从右到左进行匹配的。从右到左!所以,#nav li 我们以为这是一条很简单的规则,秒秒钟就能匹配到想要的元素,但是,但是,但是,是从右往左匹配啊,所以,会去找所有的li,然后再去确定它的父元素是不是#nav。,因此,写css的时候需要注意:

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

      关于script标签的位置

      我们大都会将script标签放在body结束标签之前  avascript的加载和执行的特点: 

             (1)载入后马上执行; 

             (2)执行时会阻塞页面后续的内容(包括页面的渲染、其它资源的下载)。原因:因为浏览器需要一个稳定的DOM树结构,而JS中很有可能有 代码直接改变                      了DOM树结构,比如使用 document.write 或 appendChild,甚至是直接使用的location.href进行跳转,浏览器为了防止出现JS修 改DOM树,需要重新构                       建DOM树的情况,所以 就会阻塞其他的下载和呈现。

     减少 JavaScript 对性能的影响的方法:

    1. 将所有的script标签放到页面底部,也就是body闭合标签之前,这能确保在脚本执行前页面已经完成了DOM树渲染。
    2. 尽可能地合并脚本。页面中的script标签越少,加载也就越快,响应也越迅速。无论是外链脚本还是内嵌脚本都是如此。
    3. 采用无阻塞下载 JavaScript 脚本的方法: 
      (1)使用script标签的 defer 属性(仅适用于 IE 和 Firefox 3.5 以上版本); 
      (2)使用动态创建的script元素来下载并执行代码;

 

posted on 2018-03-20 09:46  baoyadong  阅读(207)  评论(0编辑  收藏  举报

导航