瀏覽器中JavaScript執行原理


本章我們討論javascript在瀏覽器中是如果工作的,包括:下載、解析、執行的全過程。javascript的這些討人嫌的地方我們是知道的:

i.需要串行下載

ii.需要解析

iii.需要串行執行

而在chrchromium中,js是這樣解析的:(其實第一章末尾已經有了)

至於一些步驟的解釋,這里就不再復述了,不懂的請戳:瀏覽器渲染過程 拉至末尾。

簡直就是大魔王有木有?心中可有一萬只草泥馬奔騰而過?為什么在所有的下載線程中:

i.css加載不會阻塞頁面

ii.images加載不會阻塞頁面

iii.flash加載不會阻塞頁面

iiii.activeX加載不會阻塞頁面

iiiii.ajax還有同步異步之分

特么javascript文件就會阻塞頁面!!

 

既然如此,我們能回避UI阻塞嗎

i.在頁面底部(</body>之前)引入js腳本,原因:由於js加載阻塞頁面,而HTML是下載多少渲染多少,因此我們把它至於頁面底部,讓UI線程先執行完再加載js腳本

ii.根據具體情況,通過combo和compress減少請求數(通常在正式生產環境,我們將多個js腳本壓縮為一個)

BUT ,這並沒有真正回避UI阻塞,在</body>之前存在一個較大的腳本需要加載執行時,UI在ready后,需要較長的時間等待腳本加載和執行,在腳本ready前,UI是處於無事件響應狀態的。

iii.defer屬性

   HTML4標准中為<script>標簽定義的屬性,用於告訴瀏覽器:內容中包含document.write之類破壞DOM的腳本

   瀏覽器會無阻塞式(延遲)加載腳本,並且按頁面中<script>標簽順序串行執行js腳本

   在HTML渲染完畢之后,onload觸發之前執行

   支持:IE4.0+ ,FF3.5+

iiii.async屬性

   HTML5標准中為<script>標簽定義的屬性

   對比defer,以下相同:

    無阻塞式加載

   以下不同:

    加載完立即執行

      不保證按照頁面中<script>標簽順序執行   

    支持:FF3.6+ ,Chrome ,Opera10.5+ ,Safari ,IE9+

iiiii.不依賴瀏覽器版本的方式

    Dynamic Script DOM ,比如google分析:

   

    XHR Inject

    XHR Eval

    Script in Iframe 

還有問題嗎?當然還有:

i.並行、異步加載腳本也需要保證順序、同源策略、CDN、緩存等因素的影響

ii.沒有通用的解決方案,不過我們可以:

  使用LABjs || requireJS || seaJS 等管理我們的腳本加載

  服務端combo腳本

iii.以上可以相對完美的解決腳本下載問題,但這並不能解決腳本執行阻塞的問題

  異步大法好

 

關於異步

i.你是否認為: 異步 == (方法 + 回調) ? 呵呵 ... 你懂得! 冒泡排序的異步例子:

var innerLoop = function (array, x, y, callback) {
 if (y < array.length - x) {
  compare(array[y], array[y + 1], function (r) {
   if (r > 0) {
    swap(array, y, y + 1, function () {
     innerLoop(array, x, y + 1, callback);
    });
   } else {
    innerLoop(array, x, y + 1, callback);
   }
  });
 } else {
  callback();
 }
}

outerLoop(array, 0, function () {
 console.log("done!");
}
);
var compare = function (x, y, callback) {
 setTimeout(10, function () {
  callback(x - y);
 });
}

var swap = function (a, i, j, callback) {
 var t = a[i]; a[i] = a[j]; a[j] = t;
 repaint(a);

 setTimeout(20, callback);
}

var outerLoop = function (array, x, callback) {
 if (x < array) {
  innerLoop(array, x, 0, function () {
   outerLoop(array, x + 1, callback);
  });
 } else {
 callback();
 }
}

ii.你是否認為: 瀏覽器是單線程執行的 ?

iii.你是否使用 setTimeout || setInterval 模擬過多線程 ?

iiii.異步編程是有難度的:

   破壞了代碼的局部性

   難以應用於需要保持順序的場景

   難以處理異常及取消

   難以操作異步之間的協作及組合

問題根源:

i.javascript是單線程語言

   不能創建線程

   不能開展並行任務

   不能對線程操作

ii.阻塞UI渲染

如何解決:

i.瀏覽器並不是單線程的貨,我們可以利用如下異步線程:

     資源下載線程(javacript、images、css、object)

     ajax線程

     web worker線程

     setTimeout模擬多線程

 

總結

我們可以使用各種組合方式、現代瀏覽器的新特性去處理這些問題,總而言之,沒有一種方案是通用的。我們需要在對應的場景中找出最合適的方案,而這些方案無非是圍繞這些原理做出的變體。


免責聲明!

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



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