加載 Javascript 最佳實(shí)踐
相信很多與頁(yè)面打過(guò)交道的同學(xué)都對(duì) Yahoo 的 Best Practices for Speeding Up Your Web Site 不陌生。而這 35 條最佳實(shí)踐中,對(duì) Javascript 的加載順序的要求是:Put Scripts at the Bottom。因?yàn)楦鶕?jù) HTTP/1.1 specification 看來(lái),在同一時(shí)間加載兩個(gè)文件是最理想的,而 Javascript 腳本會(huì)阻礙平行下載。Steve 說(shuō)那是 2008 – 2009 那個(gè)時(shí)代用的?,F(xiàn)在,加載 Javascript 已經(jīng)有了革命性的化變。

在開(kāi)講之前,有一個(gè)必須解決的問(wèn)題是:為什么我們要把 JS 文件放在 </body> 之前的最底部。根本原因是,它不能平行下載。而其實(shí)并不是所有瀏覽器都不支持?,F(xiàn)在大部分瀏覽器都支持 Script 的平行下載,除了老掉牙的 IE6&7、Firefox 2&3.0、 Safari 3、Chrome 1。但我們最熟悉的老掉牙同學(xué) IE6 (或以IE為核的那些殼)還是中國(guó)(甚至世界上)市場(chǎng)上占用率最高的瀏覽器,因此我們需要一個(gè)折衷的方案。
一、分析
我們有6種方法可以實(shí)現(xiàn)平行(NON-Blocking)下載:
- XHR Eval – 用 XHR 下載,并
eval()執(zhí)行 responseText.。 - XHR Injection – 用 XHR 下載,在頁(yè)面中動(dòng)態(tài)創(chuàng)建一個(gè) script 元素,并將 responseText 作為其 text 。
- Script in Iframe – 把腳本放在 HTML 中,使用 ifame 來(lái)下載它。
- Script DOM Element – 動(dòng)態(tài)創(chuàng)建一個(gè) script 元素,把
src指向腳本URL. - Script Defer – 給 script 標(biāo)添加
defer屬性 document.writeScript Tag – 利用document.write把<script src="">添加到 HTML 中。但這個(gè)只對(duì) IE 有效。
兼容性可看下圖:
| Technique | Parallel Downloads | Differ | Existing Scripts | Busy Indicators | Ensures Order | Size (bytes) |
|---|---|---|---|---|---|---|
| XHR Eval | IE, FF, Saf, Chr, Op | no | no | Saf, Chr | - | ~500 |
| XHR Injection | IE, FF, Saf, Chr, Op | no | yes | Saf, Chr | - | ~500 |
| Script in Iframe | IE, FF, Saf, Chr, Op | no | no | IE, FF, Saf, Chr | - | ~50 |
| Script DOM Element | IE, FF, Saf, Chr, Op | yes | yes | FF, Saf, Chr | FF, Op | ~200 |
| Script Defer | IE, Saf4, Chr2, FF3.1 | yes | yes | IE, FF, Saf, Chr, Op | IE, FF, Saf, Chr, Op | ~50 |
| document.write Script Tag | IE, Saf4, Chr2, Op | yes | yes | IE, FF, Saf, Chr, Op | IE, FF, Saf, Chr, Op | ~100 |
二、方案
對(duì)于究竟應(yīng)該使用哪種方案。這完全取決于你需要自身的需要。這張圖描述了什么時(shí)候使用什么方法:
從總體上看來(lái),Script DOM Element 是比較好的方案。NCZ 的博客上提過(guò),目前最好的技術(shù)是:
- 創(chuàng)建兩個(gè) JavaScript 文件。第一個(gè)文件只提供動(dòng)態(tài)下載 Javascript 的代碼,第二個(gè)文件則包含所有其他頁(yè)面所需腳本的文件。
- 像
<script>在頁(yè)部(</body> 之前)引入第一個(gè)文件。 創(chuàng)建第二個(gè) <script>來(lái)執(zhí)行下載第二個(gè) Javascript 文件的函數(shù)和其他的初始化代碼。
三、實(shí)現(xiàn)代碼
根據(jù)上面的提到的技術(shù)。NCZ 推薦第一個(gè)文件只包含相應(yīng)的實(shí)現(xiàn)第二個(gè)文件動(dòng)態(tài)加載的代碼:
function loadScript(url, callback){
var script = document.createElement("script")
script.type = "text/javascript";
if (script.readyState){ //IE
script.onreadystatechange = function(){
if (script.readyState == "loaded" ||
script.readyState == "complete"){
script.onreadystatechange = null;
callback();
}
};
} else { //Others
script.onload = function(){
callback();
};
}
script.src = url;
document.getElementsByTagName("head")[0].appendChild(script);
}
然后,我們可以在頁(yè)面中這樣做:
<script type="text/javascript" src="http://your.cdn.com/first.js"></script>
<script type="text/javascript">
loadScript("http://your.cdn.com/second.js", function(){
//初始化你的代碼
});
</script>
在 HTML5 上,我們可以使用 async 屬性。這個(gè) HTML 屬性的作用正是我們需要的 NON-Blocking 下載技術(shù)。雖然目前支持的瀏覽器并不多(似乎只有 Firefox 3.6+ ?),但給需要平行下載的 Javascript(按照方案看來(lái),一般是第一個(gè) JS 文件) 加上這個(gè)屬性,也不會(huì)影響其他不支持的瀏覽器,所以,是推薦使用的。
四、實(shí)踐
YUI3 的 Loader 使用了 NCZ 的這樣的方法。而在支付寶。我們也使用了類似的方法。這里簡(jiǎn)單說(shuō)一下。
<script type="text/javascript" charset="utf-8">
// 配置 combo 服務(wù)的 PATH
araleConfig = {
combo_host: "http://domain.com",
combo_path: '/path/to/the/compressed/file'
}
</script>
<script type="text/javascript" src="core.js"></script>
在使用的時(shí)候,再利用 Loader.use() 來(lái)實(shí)現(xiàn)代碼的動(dòng)態(tài)加載。當(dāng)然,這里不僅僅是動(dòng)態(tài)加載,還有一定的緩存機(jī)制在里面。建議你查看相關(guān)的 combo 服務(wù)的技術(shù)。目前支付寶前端架構(gòu)組的工友們,已經(jīng)在這一塊取得了一些不錯(cuò)的進(jìn)展(根據(jù)測(cè)試報(bào)告,速度是非常不錯(cuò)的,可能會(huì)在適當(dāng)?shù)臅r(shí)候開(kāi)源出來(lái))。
五、總結(jié)
前端性能優(yōu)化方面。還有很多東西可以做。并且,隨著 HTML5 技術(shù)的出現(xiàn)和 Javascript 技術(shù)的不斷創(chuàng)新,相信還有更多東西是值得期待。前端們,加油吧,未來(lái)有很多東西應(yīng)該是由你來(lái)主導(dǎo)的。
Reference:
相關(guān)文章
js實(shí)現(xiàn)類似新浪微博首頁(yè)內(nèi)容漸顯效果的方法
這篇文章主要介紹了js實(shí)現(xiàn)類似新浪微博首頁(yè)內(nèi)容漸顯效果的方法,實(shí)例分析了漸顯效果的實(shí)現(xiàn)要點(diǎn)與方法,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-04-04
JavaScript調(diào)試技巧之console.log()詳解
對(duì)于JavaScript程序的調(diào)試,相比于alert(),使用console.log()是一種更好的方式,原因在于:alert()函數(shù)會(huì)阻斷JavaScript程序的執(zhí)行,從而造成副作用;而console.log()僅在控制臺(tái)中打印相關(guān)信息,因此不會(huì)造成類似的顧慮2014-03-03
淺談nodeName,nodeValue,nodeType,typeof 的區(qū)別
本文主要簡(jiǎn)單介紹了nodeName,nodeValue,nodeType,typeof 的區(qū)別,算是知識(shí)點(diǎn)的一個(gè)小總結(jié),希望對(duì)小伙伴們有所幫助2015-01-01
ES6 javascript中Class類繼承用法實(shí)例詳解
這篇文章主要介紹了ES6 javascript中Class類繼承用法,結(jié)合實(shí)例形式較為詳細(xì)的分析了ES6繼承的基本用法、相關(guān)屬性、方法與使用技巧,需要的朋友可以參考下2017-10-10
JavaScript實(shí)現(xiàn)twitter puddles算法實(shí)例
這篇文章主要介紹了JavaScript實(shí)現(xiàn)twitter puddles算法實(shí)例,本文源自twitter的一道面試題,本文使用js解開(kāi)了這首題,需要的朋友可以參考下2014-12-12
JavaScript 筆記二 Array和Date對(duì)象方法
本篇主要講解本地對(duì)象Array和Date的各種方法。2010-05-05
javascript實(shí)時(shí)顯示當(dāng)天日期的方法
這篇文章主要介紹了javascript實(shí)時(shí)顯示當(dāng)天日期的方法,可實(shí)時(shí)顯示當(dāng)前日期及星期的功能,非常簡(jiǎn)單實(shí)用,需要的朋友可以參考下2015-05-05


