使用外聯的Javascript和CSS
我們應該使用外聯拓展Javascript和Css還是在頁面中內聯他們?我們將會發現,使用拓展文件通常會更好。
內聯VS外聯
讓我們開始來權衡下內聯和外聯這兩種方式。
在原始條件下,內聯比較快
我制作了兩個例子來說明內聯JS和CSS比外聯引用他們有更快的響應。
內聯JS和CSS http://stevesouders.com/hpws/inlined.php
外聯JS和CSS http://stevesouders.com/hpws/external.php
內聯例子包含一個87K大的HTML文檔,所有的JS和CSS都在頁面里面。外聯的例子包含一個7K的HTML文檔,一個59K的樣式文件,和三個JS(1K,11K和9K),總共87K,雖然總大小是一樣的,但是內聯要去外聯的例子快30%-50%。主要原因是因為外聯的例子有多個HTTP請求的開銷,即便部件是平行下載的,但還是要比內聯來的慢。
盡管是這個結構,但在真實的世界中,使用外聯文件通常產出更快的頁面訪問。這個得益于外聯文件不需要獲取,JS和CSS有機會被瀏覽器緩存。HTML文檔至少包含動態內容,通常不配置為可緩存。內聯JS和CSS每一次HTML文件請求時,都會去下載。另一邊,如果JS和CSS被瀏覽器緩存,HTML文檔的尺寸減少了,因為減少了好幾個HTTP請求。
關鍵因素是外聯JS和CSS與HTML文檔相關緩存的頻繁度,這個比較難評估,可以使用下面的測量標準。
頁面訪問數量
每個用戶的頁面瀏覽量越少,就是該使用內聯JS和CSS的有力論據。想象一下,一個典型的用戶訪問你的網站每月一次,在每次訪問中間,任何的JS和CSS緩存都可能已經失效,即便部件有一個很長的expire頭。
另一方面,如果一個典型用戶有很多的頁面訪問量,瀏覽器更可能有外聯部件的緩存。使用JS和CSS外聯文件的益處是隨著每月每個用戶額訪問量或者每次session每個用戶的頁面訪問量而水漲船高的。
空緩存VS命中緩存
比較內聯和外聯時,知道緩存外聯文件的潛能非常重要。我們在Yahoo上測量,發現單個用戶一天至少命中緩存一次的人數在40%-60%之間。相同的研究表明頁面訪問命中緩存的數量在75%-85%之間。注意第一個統計的是“單個用戶”而第二個統計的是“頁面訪問"。用戶可能一天中碰到一次空緩存訪問,但是更多的后來頁面訪問都來自命中緩存。
這些度量非常依賴網站的類型。知道這些數據幫助評估使用拓展文件相對內聯潛在的好處。如果你的網站對你的用戶有一個較高的命中緩存,使用外聯文件更好。否則,內聯會使一種更好的選擇。
部件重用
部件在不同網頁中重用慮比較大,使用外聯;如果重用慮低,使用內聯
多因數考慮典型的結果
權衡內聯和外聯,關鍵是訪問多個HTML請求相關的被緩存的外聯JS和CSS的頻率。在上面部分說的,我描述了三個指標(頁面訪問量,空緩存VS命中緩存,和組件重用)能夠幫助你做出最好的決定。
很多網站都在這三個指標之中,他們每個用戶每月訪問5-15個頁面,每個用戶每次session訪問2-5個頁面。40%-60%用戶每天有一次命中緩存,每天頁面訪問的75%-85%命中緩存。
考慮這些指標,最好的解決辦法是發布JS和CSS為外聯文件。
首頁
唯一的例外是內聯使用在首頁上。
兩者結合的最佳實踐
兩個技術在這里介紹,讓你同時獲得內聯和外聯兩者的益處。
提前下載
首頁是網頁訪問的開始,對于首頁我們想要內聯js和css,但是對于所有的二級頁面使用外聯文件。這個完全可以在首頁加載完成后,動態地下載二級頁面的外聯文件。使得外聯文件駐留在瀏覽器緩存中,為用戶繼續訪問其他頁面而使用。
預下載例子:
http://stevesouders.com/hpws/post-onload.php
<script type="text/javascript">
function doOnload( ) {
setTimeout("downloadComponents( )", 1000);
}
window.onload = doOnload;
// Download external components dynamically using JavaScript.
function downloadComponents( ) {
downloadJS("http://stevesouders.com/hpws/testsma.js");
downloadCSS("http://stevesouders.com/hpws/testsm.css");
}
// Download a script dynamically.
function downloadJS(url) {
var elem = document.createElement("script");
elem.src = url;
document.body.appendChild(elem);
}
// Download a stylesheet dynamically.
function downloadCSS(url) {
var elem = document.createElement("link");
elem.rel = "stylesheet";
elem.type = "text/css";
elem.href = url;
document.body.appendChild(elem);
}
</script>
動態內聯
如果一個首頁的服務端知道一個部件是否在瀏覽器緩存中,它能夠做出決定是否使用內聯還是外聯文件。雖然沒有辦法讓服務端知道瀏覽器緩存中有什么,但cookie似乎是有用的。返回服務端一個基于session的cookie,服務端基于cookie值出現使用外聯,不出現使用內聯;
動態內聯的例子:
http://stevesouders/hpws/dynamic-inlinling.php
<?php
if ( $_COOKIE["CA"] ) {
// If the cookie is present, it's likely the component is cached.
// Use external files since they'll just be read from disk.
echo <<<OUTPUT
<link rel="stylesheet" href="testsm.css" type="text/css">
<script src="testsma.js" type="text/javascript"></script>
OUTPUT;
}
else {
// If the cookie is NOT present, it's likely the component is NOT cached.
// Inline all the components and trigger a post-onload download of the files.
echo "<style>\n" . file_get_contents("testsm.css") . "</style>\n";
echo "<script type=\"text/javascript\">\n" . file_get_contents("testsma.js") .
"</script>\n";
// Output the Post-Onload Download JavaScript code here.
echo <<<ONLOAD
<script type="text/javascript">
function doOnload( ) {
setTimeout("downloadComponents( )", 1000);
}
window.onload = doOnload;
// Download external components dynamically using JavaScript.
function downloadComponents( ) {
document.cookie = "CA=1";
[snip...]
ONLOAD;
}
?>