浏览器加载和渲染HTML的过程(标准定义的过程以及现代浏览器的优化)

先看一下标准定义的浏览器渲染过程(网上找的):javascript

浏览器打开网页的过程

  1. 用户第一次访问网址,浏览器向服务器发出请求,服务器返回html文件;
  2. 浏览器开始载入html代码,发现 head 标签内有一个 link 标签引用外部CSS或JS文件;
  3. 浏览器又发出CSS及JS文件的请求,服务器返回这个CSS,JS文件;
  4. 浏览器继续载入html中 body 部分的代码,而且CSS,JS文件已经拿到手了,能够开始渲染页面了;
  5. 浏览器在代码中发现一个 img 标签引用了一张图片,向服务器发出请求。此时浏览器不会等到图片下载完,而是继续渲染后面的代码
  6. 服务器返回图片文件,因为图片占用了必定面积,影响了页面布局,所以浏览器须要回过头来从新渲染这部分代码;
  7. 浏览器发现了一个包含一行Javascript代码的 script 标签,赶快执行它;
  8. Javascript脚本执行了这条语句,它命令浏览器隐藏掉代码中的某个 div (style.display=”none”)。杯具啊,忽然就少了这么一个元素,浏览器不得不从新渲染这部分代码;
  9. 终于等到了 html 的到来,浏览器泪流满面……

浏览器加载和渲染html的顺序

  1. IE浏览器下载的顺序是从上到下,渲染的顺序也是从上到下,下载和渲染是同时进行的。
  2. 在渲染到页面的某一部分时,其上面的全部部分都已经下载完成(并非说全部相关联的元素都已经下载完)
  3. 若是遇到语义解释性的标签嵌入文件(JS脚本,CSS样式),那么此时IE的下载过程会启用单独链接进行下载。
  4. 而且在下载后进行解析,解析过程当中,中止页面全部往下元素的下载,阻塞加载
  5. 样式表在下载完成后,将和之前下载的全部样式表一块儿进行解析,解析完成后,将对此前全部元素(含之前已经渲染的)从新进行渲染。
  6. JS、CSS中若有重定义,后定义函数将覆盖前定义函数。

JS的加载

  • 不能并行下载和解析(阻塞下载)
  • web的模式是同步的,开发者但愿解析到一个script标签时当即解析执行脚本,并阻塞文档的解析直到脚本执行完;若是脚本是外引的,当引用了JS的时候,浏览器发送一个js request就会一直等待该request的返回,这个过程也是同步的,会阻塞文档的解析直到资源被请求到。由于浏览器须要一个稳定的DOM树结构,而JS中颇有可能有代码直接改变了DOM树结构,好比使用 document.write 或 appendChild,甚至是直接使用的location.href进行跳转,浏览器为了防止出现JS修改DOM树,须要从新构建DOM树的状况,因此就会阻塞其余的下载和呈现。这个模式保持了不少年,而且在html4及html5中都特别指定了。开发者能够将脚本标识为defer,以使其不阻塞文档解析,并在文档解析结束后执行。Html5增长了标记脚本为异步的选项,以使脚本的解析执行使用另外一个线程。

 

这里面有几个点须要说明一下:css

  1.咱们知道浏览器的处理过程是解析html生成DOM tree->根据DOM tree和样式表生成render tree->渲染render tree展现。浏览器为了让用户更快的看到页面,因此是边解析html生成局部的DOM tree,浏览器就生成部分render tree而后展现出来。html

  2.此过程当中有两种外部资源是阻塞脚本执行,从而阻塞渲染的,分别是外部js和外部css。外部js是阻塞了DOM tree的生成,由于浏览器须要一个稳固的DOM tree,而js可能破坏这个结构(固然其中也可能会更改样式【注意是样式而不是样式表】,可是这个不阻塞也不会有影响的);外部css样式表也会阻塞脚本的执行,理论上,既然样式表不改变Dom树,也就没有必要停下文档的解析等待它们,然而,存在一个问题,脚本可能在文档的解析过程当中请求样式信息,若是样式尚未加载和解析,脚本将获得错误的值,显然这将会致使不少问题,这看起来是个边缘状况,但确实很常见。Firefox在存在样式表还在加载和解析时阻塞全部的脚本,而Chrome只在当脚本试图访问某些可能被未加载的样式表所影响的特定的样式属性时才阻塞这些脚本。html5

  3.其他外部资源是不阻塞渲染的,好比图片,咱们能看到不少时候页面大致的框架都呈现出来了,就是图片的位置没有显示出来的状况,等到图片下载下来之后再从新渲染。java

 

现代浏览器的优化:jquery

  按照标准的浏览器渲染和下载过程。下面的代码加载外部资源的顺序应该和资源在html中的顺序一致。其中head中添加了一个外部资源请求http://hm.baidu.com/hm.js?a041a0f4ff93aef6aa83f34134331a1d应该在全部样式以前加载  web

<html>
<head>
    ...
    <!--百度统计代码-->
    <script>
    var _hmt = _hmt || [];
    (function() {
        var host=document.location.hostname;
        if(/lcfarm.com$/ig.test(host)){
          var hm = document.createElement("script");
          hm.src = "//hm.baidu.com/hm.js?a041a0f4ff93aef6aa83f34134331a1d";
          var s = document.getElementsByTagName("script")[0]; 
          s.parentNode.insertBefore(hm, s);
        }
    })();
    </script>
    <link rel="stylesheet" type="text/css" href="//static.lcfarm.com/pc-dist/pkg/index.html_aio_f9db6a6.css">
    <link rel="stylesheet" type="text/css" href="//static.lcfarm.com/pc-dist/common/css/common_530eedd.css">
    <link rel="stylesheet" type="text/css" href="//static.lcfarm.com/pc-dist/css/index_8b620da.css">
    <link rel="stylesheet" type="text/css" href="//static.lcfarm.com/pc-dist/pkg/index.html_aio_2_2379650.css">
</head>
<body>
    ...
    <script type="text/javascript" data-loader="" src="//static.lcfarm.com/pc-dist/common/dep/mod_36ad799.js"></script>
    <script type="text/javascript" data-loader="" src="//static.lcfarm.com/pc-dist/common/dep/jquery_c07f226.js"></script>
    <script type="text/javascript" src="//static.lcfarm.com/pc-dist/common/js/jquery/jquery.cookie_546183c.js"></script>
    <script type="text/javascript" src="//static.lcfarm.com/pc-dist/pkg/common_85ea494.js"></script>
    <script type="text/javascript" src="//static.lcfarm.com/pc-dist/pkg/index.html_aio_350303c.js"></script>
</body>
</html>

  可是实际上在chrome。Firefox、ie8+等浏览器中却发现是以下效果(使用https://www.webpagetest.org/测试)chrome

  

  为何?这就是预解析(Speculative parsing)浏览器

  Webkit和Firefox都作了这个优化,当执行脚本时,另外一个线程解析剩下的文档,并加载后面须要经过网络加载的资源。这种方式可使资源并行加载从而使总体速度更快。须要注意的是,预解析并不改变Dom树,它将这个工做留给主解析过程,本身只解析外部资源的引用,好比外部脚本、样式表及图片。服务器

  如上面的那张图,能够看出在执行脚本的时候与解析了一大堆的外部资源引用,并启动线程下载他们,主线程还在等待hm.js的返回。

 

  若是以为本文不错,请点击右下方【推荐】!

相关文章
相关标签/搜索