前面的章節皆在探討 JavaScript 核心,與執行環境無關;本篇則著重於 browser 上的相關 pattern。
Separation of Concerns
Concerns 有三:
Context:文件內容,即 HTML
Presentation:外觀表現,即 CSS
Behavior:使用者互動或文件動態改變,即 JavaScript
當關閉 CSS 或 JavaScript 時,應確保頁面仍可正常閱讀,且主要功能仍可正常運作
避免將 CSS 或 JavaScript 內嵌在 context 中
應直接檢測明確的 method 或 property,避免使用 user agent sniffing
DOM Scripting
避免在 loop 中存取 DOM,應 assign 其 reference 給 local variable
盡量使用 selector API(如 document.querySelector()
或 document.querySelectorAll()
),而 id=""
是尋找節點最快的方式(document.getElementById()
)
更新 DOM 會使 browser 進行 repain(重新繪製畫面)及 reflow(重新計算元素的幾何結構),因此應在 “live” DOM tree 之外進行操作(如:新增時先用 document fragment 容納所有節點,待一連串的動作完成後再將這個已定案的 fragment 加至 DOM;修改時則可先在 clone 中處理,完成後再替換原本的節點)
Events
使用 addEventListener()
/attachEvent()
時,適時加上 stopPropagation()
/cancelBubble=true
及 preventDefault()
/returnValue=false
利用 event delegation 減少 event listeners 的總量(如 div
內有十個 button
,可在 div
上加一個 listener 就好而不是在每一個 button
都加)
Long-Running Scripts
JavaScript 中雖沒有 thread,但可藉由 setTimeOut()
模擬,或使用較新的 browser 所支援的 Web Workers,以避免因 lag 而使 user 不能操作畫面
Remote Scripting
XMLHttpRequest
(AJAX)
JSONP (for cross-domain)
iframe
image beacon(只需送 request 不需接 response 時可用,response 傳 HTTP 204 為佳)
Deploying JavaScript
合併 scripts 以減少 HTTP request,可用 cat
命令操作
使用 minify 工具壓縮,縮小檔案大小
開啟 gzip 壓縮,增快載入速度
.htaccess 1
AddOutputFilterByType DEFLATE text/html text/css text/plain text/xml application/javascript application/json
使用 Expires
header,增加檔案待在 cache 的機會
.htaccess 1
2
ExpiresActive On
ExpiresByType application/x-javascript "access plus 10 years"
Loading Strategies
<script>
的 attribute 不要加上 language
或 type
等歷史遺跡,可加 defer
或 HTML5 的 async
使其不會 block 網頁的下載流程(browser 會同時下載多個檔案,但遇到外部 script 會暫停下一步下載直到該 script 完成下載並分析與執行完畢);async
尚未廣泛支援,因此可將外部 script 放置頁面底端(</body>
前),或動態加入 <script>
元素實現 asyncronous 下載(document.createElement("script")
),後者需注意各 script 檔之間的相依性(因各檔案下載完成的時機未必如同預期順序)
當頁面需在 server-side 進行複雜運算時,可使用 chunked encoding 分批傳送頁面片段,利用 server 尚未完成工作時先將部分靜態內容送給 client-side
Strategy of Loading a Big Script
lazy loading:先載入 core 使主要功能開始運作,再用 onload
動態加 <script>
載入其他次要功能(如特效、XHR 實作等)
loading on demand:需要時才載入,並在完成後執行 callback
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
require ("extra.js" , function () {
functionDefinedInExtraJS();
});
function require (file, callback) {
var script = document .getElementsByTagName('script' )[0 ],
newjs = document .createElement('script' );
newjs.onreadystatechange = function () {
if (newjs.readyState === 'loaded' || newjs.readyState === 'complete' ) {
newjs.onreadystatechange = null ;
callback();
}
};
newjs.onload = function () {
callback();
};
newjs.src = file;
script.parentNode.insertBefore(newjs, script);
}
preloading:若希望單純只下載 script 檔案而不進行分析及執行,IE 可用 image beacon,其他 browser 可用 <object>
替代 <script>