DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> JavaScript入門知識 >> 關於JavaScript >> 異步加載:ControlJS讓腳本加載更快的一個模塊
異步加載:ControlJS讓腳本加載更快的一個模塊
編輯:關於JavaScript     

關於ControlJs一共有三篇文章,這是第一部分。ControlJS是讓腳本加載更快的一個模塊(a javascript module for making scripts load faster). 三篇文章的結構分別為:

1. async loading
2. delayed execution
3.overriding document.write
關於第一部分的異步加載,這個的關鍵在於盡快將頁面作為html繪制出來,然後再用javascript進行優化,或者說用js進一步渲染。我們看到過很多網頁,展示給用戶一片空白,只是因為在等待幾百KB的js文件下載、解析、執行,而這些js是用來繪制頁面中展示給用戶看的DOM元素。

 

其實上述的情況,很容易理解–但是真正實現改進恐怕就困難的多。好幾百KB的js必須要拆散重組。那些通過js來創建網頁DOM的邏輯代碼必須全部合成到後台的服務器端去生成html。即使使用最新的服務器端JS來實現,也是一項很大的重構工程。

我又回到了Opera的Delayed Script Execution選項。一旦這個選項生效,js會被擱置起來(move aside),讓頁面首先進行渲染。而這個選項確實很棒,而且沒有網站因為開啟了這個選項而導致頁面報錯的。我也一直持續在和其他浏覽器的供應商聯系,讓他們也實現這個功能,我迫切的希望開發人員能夠盡快的使用上這個選項。

近些年來,一些網頁加速器(例如Aptimize, Strangeloop, FastSoft, CloudFlare, Torbit,和最近的mod_pagespeed)猶如雨後春筍般脫穎而出。他們修改了頁面中的HTML標簽,用來改善網頁的性能。從這些模式中,我摸索出了一個方法,比起延遲加載頁面渲染的JS,我們可以更容易的改變HTML標記來實現。

於是ControlJS誕生了!

Controlling download and execution
ControlJS的目標是讓開發員更好的控制JS的加載。關鍵是要意識到“加載”氛圍兩個步驟:下載[download](即獲取內容)和執行[execution](包含解析).為了更好的性能,這兩個步驟有必要分離控制。

在對網頁性能敏感的程序員眼中,如何控制腳本下載是一個很廣泛流行的話題。當腳本使用普通的方式(也就是<script src=”" …的形式),腳本會阻塞其他資源的下載(在新版本浏覽器中稍微好一些),同時也會阻塞頁面的渲染(所有浏覽器都有這種情況)。使用異步腳本加載(asynchronous script loading)的技術在很大程序上緩解了這個問題。我在Even Faster Web Sites中提及過幾種異步加載的技術。LABjs 和 HeadJS是提供異步加載的js模塊。雖然它們的異步技術解決了腳本下載階段的阻塞問題,但是並沒有解決腳本執行時發生的情況。

在腳本執行階段,頁面渲染和新資源下載會被阻塞。在如今網頁中的腳本越來越多,在腳本執行階段的阻塞問題就更為嚴重,尤其是在移動設備上。事實上,Gmail移動設備組考慮到腳本執行帶來的問題,它們完善了new async technique that downloads JavaScript wrapped in comments。這項技術可以使得腳本執行和下載分離。腳本會下載到客戶端(在浏覽器的緩存中),但是因為它是腳本注釋,所以在執行階段不會阻塞(因為不會執行)。當用戶使用了相關功能的時候,需要某些腳本時,會將注釋符號刪除,然後eval執行代碼。

Stoyan Stefanov, 一名優秀的性能優化前驅者,最近發布了一篇博文preloading JavaScript without execution.他用IMAGE或者OBJECT(這取決於浏覽器)來下載腳本。假設這些腳本可以緩存在客戶端中,隨後可以使用SCRIPT標簽插入腳本。這個也是在ControlJS中使用的技術。

ControlJS: how to use it
使用ControlJS涉及到三個步驟的修改

修改點#1:添加control.js

我想關於腳本加載模塊的使用,最諷刺的地方就在於,加載這些異步腳本加載種子文件是會阻塞頁面的。所以從一開始我就必須確認ControlJS是要能被異步加載的。

var cjsscript = document.createElement('script');
cjsscript.src = "control.js";
var cjssib = document.getElementsByTagName('script')[0];
cjssib.parentNode.insertBefore(cjsscript, cjssib);修改點#2:修改外鏈的腳本
下一步就是將所有外鏈腳本的標簽改為ControlJS的形式。原本的腳本引用如下

<script type="text/javascript" src="main.js"><script>SCRIPT元素的TYPE要改為”text/cjs”,SRC改為“data-cjssrc”,如下:

<script type="text/cjs" data-cjssrc="main.js"><script>修改點#3 修改內聯的腳本
大多數的頁面都會有內聯的腳本。這些腳本有一些依賴性:內聯腳本中的變量一般依賴於外鏈的腳本,反之亦然。很重要的一點是:內斂腳本和外鏈腳本的執行順序是需要保證的。因此,內聯腳本必須改變TYPE屬性的值

<script type="text/javascript">
var name = getName();
<script>修改“text/javascript”為”text/cjs”,如下:

<script type="text/cjs">
var name = getName();
<script>這樣就ok了!後續的一系列工作就交給ControlJS擔心吧!

ControlJS: how it works
現在腳本不會阻塞頁面了,因為TYPE屬性已經改為浏覽器無法識別的值了。這也就讓ControlJS可以用一種高性能的方法更好的控制腳本加載。讓我們大概看看ControlJS是如何運作的呢?當然,你也可以查看control.js 的代碼來更詳細的了解。

我們都希望能夠盡快的開始下載腳本。因為我們使用IMAGE或者OBJECT來下載腳本,所以它們不會在下載階段阻塞頁面。而且他們並不是作為SCRIPT下載的,所以它們也不會執行。ControlJS首先找出所有SCRIPT的,並且type為”text/cjs”的標簽。如果腳本有一個DATA-CJSSRC,那麼IMAGE(IE和Opera浏覽器)或者OBJECT(其他浏覽器)就會根據它們的URL動態的創建出來。(你可以查看Stoyan’s post去了解更詳細的內容)。

一般來說,ControlJS會在window load的時間之後進入執行階段(當然也可以立刻執行代碼或者某個DOM元素加載完畢了)。ControlJS會第二次遍歷所有的腳本,確保它們都正確的出現在頁面中。如果這個腳本是一個內聯腳本,那麼它的代碼會被執行。如果這個腳本是一個外鏈腳本,由IMAGE或者OBJECT動態下載下來的,那麼它會作為一個SCRIPT標簽插入到頁面中,那麼它的代碼也會隨之解析並且執行。如果IMAGE或者OBJECT並沒有下載結束,那麼會在一個短暫的時間間隔之後(a short timeout),重新進入剛才的遍歷流程。

後續的文章中我還會討論關於document.write的功能,以及跳過執行階段。這篇中,我們首先來看一個簡單的異步加載的例子。

Async example
為了能更好展示異步加載的情況,我創建了一個文件,文件頂部包含三個腳本:

•main.js – 耗費4秒下載
•一段內聯腳本會使用main.js的一個變量
•page.js – 耗費2秒下載,使用內聯腳本的一個變量
我讓page.js的下載時間比main.js的下載時間短,是為了確認這些腳本可以以正確的順序執行(盡管page.js下載更快)。我同事也包含了內聯的腳本,因為這也是很多頁面的實際情況(例如Google Analytics),但是很多腳本加載器並不支持內聯腳本的執行順序。

Async withOUT ControlJS是一個基本范例。它使用了最普通的方式加載腳本。可以看一下如下圖所示的IE8下的HTTP瀑布圖(使用HttpWatch).IE8比IE6和IE7要好 – 能夠使main.js和page.js並行加載。但是所有的IE都會因為腳本加載而阻塞圖片的下載。所以images1-4都延遲了。在所有浏覽器中,頁面渲染都會被阻塞。在圖示中也可以看出,main.js阻塞渲染長達4秒鐘(綠色的豎線表示頁面開始渲染時間)

 

Async WITH ControlJS 演示了ControlJS是如何解決由於腳本引發的阻塞問題。不像上面的例子,腳本和圖片會並行加載。同時頁面渲染也是立刻開始的。如果你同時在浏覽器中演示這兩個頁面,你會發現ControlJS的頁面會快很多。當然,你也發現在下面的圖示中多了3個請求,一個是Control.js – 這個是用來異步加載腳本用的代碼。另外兩個請求時因為main.js和page.js下載了兩次。第一次是使用IMAGE或者OBJCET下載,第二次是使用SCRIPT標簽加入頁面用來執行代碼的。因為main.js和page.js已經存在在浏覽器緩存中了,所以他們不需要額外的下載時間。只是短暫的緩存讀取時間(也就是那兩根很細的藍色線)。

The ControlJS project
ControlJS是在Apache License下面的開源項目。你可以在ControlJS Google Code project中找到control.js的代碼。關於它的討論可以在ControlJS Google Group.關於上面提到的例子放在我的站點 ControlJS Home Page.我只在大多數的浏覽器中測試了,如果要投入到大規模的產品環境中,請進行更詳盡的測試。

Only part1
這只是ControlJS的第一部分。目前看來似乎已經解決了所有問題了。如果我們只是需要異步加載,那麼其他的一些技術其實也已經實現了。不過我的目標是不能讓腳本阻塞頁面的渲染。我們就必須面臨一個問題,如果處理document.write.另一個方面就是類似於Gmail的移動組實現的- 下載腳本同時在執行階段不會阻塞頁面渲染。我們會在下面的兩篇博文中詳細分析。

XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved