一般說來,web前端指網站業務邏輯之前的部分,包括瀏覽器加載、網站視圖模型、圖片服務、CDN服務等,主要優化手段有瀏覽器訪問、使用反向代理才、CDN等。
1、減少http請求,合理瀏覽器緩存
2、啟用壓縮:HTML、CSS、javascript文件啟用GZip壓縮可達到較好的效果
3、CSS Sprites:合並 CSS圖片,減少請求數的又一個好辦法。
4、LazyLoad Images:在頁面剛加載的時候可以只加載第一屏,當用戶繼續往后滾屏的時候才加載后續的圖片
5、CSS放在頁面最上部,javascript放在頁面最下面:讓瀏覽器盡快下載CSS渲染頁面
6、異步請求Callback(就是將一些行為樣式提取出來,慢慢的加載信息的內容)
在某些頁面中可能存在這樣一種需求,需要使用 script標簽來異步的請求數據。類似:
<span style="font-size:14px;">/*Callback 函數*/
function myCallback(info){
//do something here
}
HTML:
Callback返回的內容 :
myCallback('Hello world!');
</span>
像以上這種方式直接在頁面上寫 <script> 對頁面的性能也是有影響的,即增加了頁面首次加載的負擔,推遲了 DOMLoaded和window.onload 事件的觸發時機。如果時效性允許的話,可以考慮在 DOMLoaded事件觸發的時候加載,或者使用 setTimeout方式來靈活的控制加載的時機。
7、減少cookie傳輸
一方面,cookie包含在每次請求和響應中,太大的cookie會嚴重影響數據傳輸,因此哪些數據需要寫入cookie需要慎重考慮,盡量減少cookie中傳輸的數據量。另一方面,對於某些靜態資源的訪問,如CSS、script等,發送cookie沒有意義,可以考慮靜態資源使用獨立域名訪問,避免請求靜態資源時發送cookie,減少cookie傳輸次數。
8、Javascript代碼優化
(1). DOM
a.HTML Collection(HTML收集器,返回的是一個數組內容信息)
在腳本中 document.images、document.forms、getElementsByTagName()返回的都是HTMLCollection類型的集合,在平時使用的時候大多將它作為數組來使用,因為它有 length屬性,也可以使用索引訪問每一個元素。不過在訪問性能上則比數組要差很多,原因是這個集合並不是一個靜態的結果,它表示的僅僅是一個特定的查詢,每次訪問該集合時都會重新執行這個查詢從而更新查詢結果。所謂的“訪問集合” 包括讀取集合的 length屬性、訪問集合中的元素。
因此,當你需要遍歷 HTML Collection的時候,盡量將它轉為數組后再訪問,以提高性能。即使不轉換為數組,也請盡可能少的訪問它,例如在遍歷的時候可以將 length屬性、成員保存到局部變量后再使用局部變量。
b. Reflow & Repaint
除了上面一點之外, DOM操作還需要考慮瀏覽器的Reflow和Repaint ,因為這些都是需要消耗資源的。
(2). 慎用 with
with(obj){ p = 1}; 代碼塊的行為實際上是修改了代碼塊中的執行環境 ,將obj放在了其作用域鏈的最前端,在 with代碼塊中訪問非局部變量是都是先從 obj上開始查找,如果沒有再依次按作用域鏈向上查找,因此使用 with相當於增加了作用域鏈長度。而每次查找作用域鏈都是要消耗時間的,過長的作用域鏈會導致查找性能下降。
因此,除非你能肯定在 with代碼中只訪問 obj中的屬性,否則慎用 with,替代的可以使用局部變量緩存需要訪問的屬性。
(3). 避免使用 eval和 Function
每次 eval 或Function 構造函數作用於字符串表示的源代碼時,腳本引擎都需要將源代碼轉換成可執行代碼。這是很消耗資源的操作 —— 通常比簡單的函數調用慢 100倍以上。
eval 函數效率特別低,由於事先無法知曉傳給 eval 的字符串中的內容,eval在其上下文中解釋要處理的代碼,也就是說編譯器無法優化上下文,因此只能有瀏覽器在運行時解釋代碼。這對性能影響很大。
Function 構造函數比 eval略好,因為使用此代碼不會影響周圍代碼 ;但其速度仍很慢。
此外,使用 eval和 Function也不利於Javascript 壓縮工具執行壓縮。
(4). 減少作用域鏈查找
前文談到了作用域鏈查找問題,這一點在循環中是尤其需要注意的問題。如果在循環中需要訪問非本作用域下的變量時請在遍歷之前用局部變量緩存該變量,並在遍歷結束后再重寫那個變量,這一點對全局變量尤其重要,因為全局變量處於作用域鏈的最頂端,訪問時的查找次數是最多的。
低效率的寫法:
<span style="font-size:14px;">// 全局變量
var globalVar = 1;
function myCallback(info){
for( var i = 100000; i--;){
//每次訪問 globalVar 都需要查找到作用域鏈最頂端,本例中需要訪問 100000 次
globalVar += i;
}
}
</span>
更高效的寫法:
<span style="font-size:14px;">// 全局變量
var globalVar = 1;
function myCallback(info){
//局部變量緩存全局變量
var localVar = globalVar;
for( var i = 100000; i--;){
//訪問局部變量是最快的
localVar += i;
}
//本例中只需要訪問 2次全局變量
在函數中只需要將 globalVar中內容的值賦給localVar 中
globalVar = localVar;
}
</span>
此外,要減少作用域鏈查找還應該減少閉包的使用。
(5). 數據訪問
Javascript中的數據訪問包括直接量 (字符串、正則表達式 )、變量、對象屬性以及數組,其中對直接量和局部變量的訪問是最快的,對對象屬性以及數組的訪問需要更大的開銷。當出現以下情況時,建議將數據放入局部變量:
a. 對任何對象屬性的訪問超過 1次
b. 對任何數組成員的訪問次數超過 1次
另外,還應當盡可能的減少對對象以及數組深度查找。
(6). 字符串拼接
在 Javascript中使用”+”號來拼接字符串效率是比較低的,因為每次運行都會開辟新的內存並生成新的字符串變量,然后將拼接結果賦值給新變量。與之相比更為高效的做法是使用數組的 join方法,即將需要拼接的字符串放在數組中最后調用其 join方法得到結果。不過由於使用數組也有一定的開銷,因此當需要拼接的字符串較多的時候可以考慮用此方法。
9、CSS選擇符優化
在大多數人的觀念中,都覺得瀏覽器對 CSS選擇符的解析式從左往右進行的,例如
#toc A { color: #444; }這樣一個選擇符,如果是從右往左解析則效率會很高,因為第一個 ID選擇基本上就把查找的范圍限定了,但實際上瀏覽器對選擇符的解析是從右往左進行的。如上面的選擇符,瀏覽器必須遍歷查找每一個 A標簽的祖先節點,效率並不像之前想象的那樣高。根據瀏覽器的這一行為特點,在寫選擇符的時候需要注意很多事項,有興趣的童鞋可以去了解一下。
CDN加速
CDN(contentdistribute network,內容分發網絡)的本質仍然是一個緩存,而且將數據緩存在離用戶最近的地方,使用戶以最快速度獲取數據,即所謂網絡訪問第一跳,如下圖。
由於CDN部署在網絡運營商的機房,這些運營商又是終端用戶的網絡服務提供商,因此用戶請求路由的第一跳就到達了CDN服務器,當CDN中存在瀏覽器請求的資源時,從CDN直接返回給瀏覽器,最短路徑返回響應,加快用戶訪問速度,減少數據中心負載壓力。
CDN緩存的一般是靜態資源,如圖片、文件、CSS、script腳本、靜態網頁等,但是這些文件訪問頻度很高,將其緩存在CDN可極大改善網頁的打開速度。
反向代理
傳統代理服務器位於瀏覽器一側,代理瀏覽器將http請求發送到互聯網上,而反向代理服務器位於網站機房一側,代理網站web服務器接收http請求。