浏览器渲染页面过程

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浏览器渲染页面过程相关的知识,希望对你有一定的参考价值。

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

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

二、JS的加载

1、浏览器对于javascript的运行有两大特性:1)载入后马上执行,2)执行时会阻塞页面后续的内容(包括页面的渲染、其它资源的下载)。于是,如果有多个js文件被引入,那么对于浏览器来说,这些js文件被被串行地载入,并依次执行。因为javascript可能会来操作HTML文档的DOM树,所以,浏览器一般都不会像并行下载css文件并行下载js文件,因为这是js文件的特殊性造成的。所以,如果你的javascript想操作后面的DOM元素,基本上来说,浏览器都会报错说对象找不到。因为Javascript执行时,后面的HTML被阻塞住了,DOM树时还没有后面的DOM结点。所以程序也就报错了。

2、当所有样式表都下载完成以后页面才开始一起解析css文件开始渲染文件。

3、因为浏览器的加载是从上到下一行一行的加载的,所以如果页面同事定义了两个相同命名的js函数,后面的函数会覆盖前面的函数。

三、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文件,重新渲染页面。 

四、 DOMContentLoaded事件

DOMContentLoaded事件在许多Webkit浏览器以及IE9上都可以使用。
DOMContentLoaded事件本身不会等待CSS文件、图片、iframe加载完成。
触发时机:加载完页面,解析完所有标签(不包括执行CSS和JS),并如规范中所说的设置interactive和执行每个静态的script标签中的JS,然后触发。而JS的执行,需要等待位于它前面的CSS加载(如果是外联的话)、执行完成,因为JS可能会依赖位于它前面的CSS计算出来的样式。
 
现代浏览器会并发的预加载CSS, JS,也就是一开始就并发的请求这些资源,但是,执行CSS和JS的顺序还是按原来的依赖顺序(JS的执行要等待位于其前面的CSS和JS加载、执行完)。先加载完成的资源,如果其依赖还没加载、执行完,就只能等着。
img是否需要解码、绘图(paint)出来,确实需要等CSS加载、执行完才能知道。也就是说,CSS会阻塞img的展现!那么JS呢?
在有JS而没有CSS的页面中,img居然能够在收到数据后就立刻开始解码、绘图(paint),也就是说,JS并没有阻塞img的展现!这跟我们以前理解的JS会阻塞img资源的传统观念不太一样,看来Chrome对img的加载和展现做了新的优化。
执行顺序简单归纳为:
立即执行函数 =》domReady  =》 onload

五、js执行时机

head里的 <script>标签会阻塞后续资源的载入以及整个页面的生成 。所以很多网站把javascript放在网页的最后面,或者动用了window.onload或是docmuemt ready之类事件。
实现等待DOM被完全加载后才调用JS文件
1) 将所有的JS文件都放在</HTML>后面后再进行调用
2 )将JS代码放在标签里面
Javascript并非完全的按顺序解释执行,而是在解释之前会对Javascript进行一次“预编译”,在预编译的过程中,会把定义式的函数优先执行,也会把所有var变量创建,默认值为undefined,以提高程序的执行效率。当JavaScript引擎解析脚本时,它会在预编译期对所有声明的变量和函数进行处理。

1. 在执行前会进行类似“预编译”的操作:首先会创建一个当前执行环境下的活动对象,并将那些用var申明的变量设置为活动对象的属性,但是此时这些变量的赋值都是undefined,并将那些以function定义的函数也添加为活动对象的属性,而且它们的值正是函数的定义。

2. 在解释执行阶段,遇到变量需要解析时,会首先从当前执行环境的活动对象中查找,如果没有找到而且该执行环境的拥有者有prototype属性时则会从prototype链中查找,否则将会按照作用域链查找。遇到var a = ...这样的语句时会给相应的变量进行赋值(注意:变量的赋值是在解释执行阶段完成的,如果在这之前使用变量,它的值会是undefined) 所以,就会出现当JavaScript解释器执行下面脚本时不会报错
f();  // 调用函数,正确执行
function f(){ 
   alert(1);
}
  
f();// 调用函数,返回语法错误
var f = function(){
   alert(1);
}

上面示例中定义的函数仅作为值赋值给变量f,所以在预编译期,JavaScript解释器只能够为声明变量f进行处理,而对于变量f的值,只能等到执行期时按顺序进行赋值,自然就会出现语法错误,提示找不到对象f。

JavaScript解释器在执行脚本时,是按块来执行的。通俗地说,就是浏览器在解析HTML文档流时,如果遇到一个<script>标签,则JavaScript解释器会等到这个代码块都加载完后,先对代码块进行预编译,然后再执行。执行完毕后,浏览器会继续解析下面的HTML文档流,同时JavaScript解释器也准备好处理下一个代码块。由于JavaScript是按块执行的,所以如果在一个JavaScript块中调用后面块中声明的变量或函数就会提示语法错误。虽然说,JavaScript是按块执行的,但是不同块都属于同一个全局作用域,也就是说,块之间的变量和函数是可以共享的。

备注:document.write()会把输出写入到脚本文档所在的位置,浏览器解析完documemt.write()所在文档内容后,继续解析document.write()输出的内容,然后在继续解析HTML文档。
<script type="text/javascript">//<![CDATA[   
  document.write(‘<script type="text/javascript" src="test.js"><//script>‘);
  document.write(‘<script type="text/javascript">‘);   
  document.write(‘alert(2);‘)   
  document.write(‘alert("我是" + tmpStr);‘);   
  document.write(‘<//script>‘);    //]]>
</script> 
IE下,用Document.Write方法引用js文件时,js文件会出现尚未加载就直接调用的情况,因此建议将引用的JS文件单独放在一个script块中。以确保引用的js文件完全加载后,再继续执行后面的Document.Write内容。在js里出现同名函数后,你在web页面里调用改js函数后,总是调用页面中最后一个加载的函数。

六、jQuery DomReardy事件

在Jquery里面,我们可以看到两种写法:$(function(){}) 和$(document).ready(function(){})
这两个方法的效果都是一样的,都是在dom文档树加载完之后执行一个函数(注意,这里面的文档树加载完不代表全部文件加载完)。
而window.onload是在dom文档树加载完和所有文件加载完之后执行一个函数。也就是说$(document).ready要比window.onload先执行。

那么Jquery里面$(document).ready函数的实现:

document.ready = function (callback) {
  //兼容FF,Google
  if (document.addEventListener) {
     document.addEventListener(DOMContentLoaded, function () {
          document.removeEventListener(DOMContentLoaded, arguments.callee, false);
                callback();
          }, false)
       }
   //兼容IE
   else if (document.attachEvent) {
       document.attachEvent(onreadytstatechange, function () {
           if (document.readyState == "complete") {
              document.detachEvent("onreadystatechange", arguments.callee);
                     callback();
              }
           })
       }
  else if (document.lastChild == document.body) {
          callback();
       }
  }

  window.onload = function () {
      alert(onload);
}; document.ready(function () { alert(
ready); });

七、 DOM(文档对象模型 Document Object Model)

技术分享

 

参考:

http://www.kuqin.com/shuoit/20140303/338367.html

http://www.cnblogs.com/zhangziqiu/archive/2011/06/27/DOMReady.html

w3c HTML5规范:https://www.w3.org/TR/html5/syntax.html#the-end

DOMContentLoaded: https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded

 

以上是关于浏览器渲染页面过程的主要内容,如果未能解决你的问题,请参考以下文章

浏览器渲染页面的过程,以及重绘与重排

前端总结--性能优化

网页渲染过程

浏览器渲染页面的探讨

浏览器渲染页面过程

Spring boot:thymeleaf 没有正确渲染片段