js並行加載,順序執行

js並行加載,順序執行

<script>運行腳本或加載外部文件時,會阻塞頁面渲染,阻塞其他資源的加載。如果頁面中需要加載多個js文件,在古老瀏覽器中性能會比較糟糕。 因此有了最原始的優化原則:把腳本放在底部

如何實現js非阻塞、並行加載,甚至能保持執行順序呢?各瀏覽器表現如何?站在巨人的肩膀上,Kyle SimpsonNicholas C. ZakasSteve Souders對此有過總結和方案。

背景

1. Script DOM Element。 動態插入<script>,不會阻塞,但無法保持執行順序。但唯有Firefox可以保持執行順序,但也差點在Firefox 4 nightly的版本中去掉這個特性。

2. HTML5 async 非阻塞,加載完後立即執行,不保證順序。這個屬性不管有沒有值、值爲true或false,都是等同的效果(由於Kyle的推進,不能保證執行順序與其值無關了)。

Google Analytics的新版嵌入代碼就結合使用了上面兩個方案,如:

1
2
3
4
5
6
7
8
var ga = document.createElement('script');
ga.type = 'text/javascript';
ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www')
          + '.google-analytics.com/ga.js';
 
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);

3. IE partsandspares.co.za defer屬性。不阻塞,可以保證順序,在DOM加載完成後執行(在DOMContentLoaded之前)。

4. <script>的type屬性設爲”script/cache” 非標準的type屬性,使js文件只會被加載而不會執行。需要執行時,創建一個type屬性爲”text/javascript”的正常<script>元素,src設爲前面已經加載的js地址即可,執行順序開發者可控(執行時機也完全可控)。類似的方式也有通過<img>來做預加載的。

5. document.write。文檔流關閉後執行會清空整個頁面。

6. XHR 並行加載,執行順序可控,但有同域限制。

基本需求

Steve Souders 和 Nicholas C. Zakas 一起總結了下,認爲js加載方案必須解決以下問題

  1. 支持特性檢測
  2. 不會重複加載
  3. 支持並行加載

開發者的美好願望

Nicholas C. Zakas 幾經周折,有了以下的提案,分離js的加載和執行,方便開發者自由控制js的執行時間。

1
2
3
4
5
6
7
8
9
10
11
12
13
var script = document.createElement("script");
 
// 此屬性僅可由js動態寫入,在HTML標籤中直接寫入無效
script.preload = true;
 
// src賦值後,立即觸發加載(僅加載,不會執行js內容)
script.src = "foo.js";
 
// onpreload是需要新支持的事件,加載完成後觸發此事件
script.onpreload = function(){
    // 在需要時,將加載的js插入到DOM中,即可運行生效
    document.body.appendChild(script);
};

基於特性檢測feature detection(區別於特性推測feature inference)

var isPreloadSupported = (typeof script.preload == “boolean”);

這一特性只有在Javascript中動態賦值時生效,直接寫到HTML標籤上時是無效的。

但這只是一個提案,開發者們的美好願望,而非被瀏覽器支持的標準。目前這一提案已在LABjs中支持,Zakas本人也在積極推進此提案的標準化。

而Kyle在推進另外一種方式,即要求對含有屬性async=false的<script>保持執行順序。如果async=true,則一旦加載完則會馬上執行腳本,不會嚴格保持順序。默認地,頁面中的<script>的async屬性爲false,即保持執行順序;js創建的<script>的async屬性爲true,即加載完立即執行,不保證順序。

爲了支持特性檢測,一個由js創建的<script>標籤默認具有async=true的屬性。

Kyle的這一提案已被HTML5小組接受放入草案,在Firefox 4 nightly版本中的也已實現。

Firefox 4爲了更向HTML5標準看齊,一度在開發者版本中去掉了對動態創建<script>來加載js文件的執行順序支持

<script> elements created using document.createElement() and inserted into a document now behave according to the HTML5 specification by default. Scripts with the src attribute execute as soon as available (without maintaining ordering) and scripts without the src attribute execute synchronously.

爲此,Kyle向WebKit開發團隊抗議,提了一個bug,最終得到了如他所願的支持:

To make script-inserted scripts that have the src attribute execute in the insertion order, set .async=false on them.

Zakas很欣賞Kyle的方案,Kyle在LABjs中也支持了Zakas的提議,各瀏覽器們也這麼和諧就好了。

轉自:http://www.impng.com/web-dev/parallel-download-ordered-execute.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章