瀏覽器渲染頁面過程


一、瀏覽器加載和渲染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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM