1.文件優化
圖片優化
- 一些修飾類圖片可用CSS代替
- 將多個圖標文件整合到一張圖片中 (CSS Sprite)
- 選擇正確的圖片格式:
- gif無損壓縮,適合logo、線條等小型簡單圖像
- jpeg適合照片、漸變圖像
- PNG-8相對於GIF來講有對alpha透明通道的支持,PNG-24會比JPEG,GIF,PNG-8占用更多的存儲空間
- svg適合簡單的平面矢量形狀,復雜的渲染時需要較多計算。
- 計算圖片大小
對於一張 100 _ 100 像素的圖片來說,圖像上有 10000 個像素點,如果每個像素的值是 RGBA 存儲的話,那么也就是說每個像素有 4 個通道,每個通道 1 個字節(8 位 = 1 個字節),所以該圖片大小大概為 39KB(10000 _ 1 * 4 / 1024)。
其他文件優化
- 靜態資源使用 CDN加載
- 重要的CSS文件放head中,其他可以放底部或動態加載
- 將耗時的js代碼使用Web Workers執行
- <script>標簽
- 放在底部,避免阻塞渲染
- 動態腳本加載,向DOM中插入<script>標簽
- 給標簽加上 defer或async
- defer ,表示該文件會並行下載,但是會放到 HTML 解析完成后順序執行。
- 沒有任何依賴的JS文件可以加上async,表示加載和渲染后續文檔元素的過程將和 JS 文件的加載與執行並行無序進行。
2.懶執行、懶加載、預加載、預渲染、DNS預解析
懶執行 | 將某些邏輯延遲到使用時再計算,可用於首屏優化 | 定時器,事件觸發 |
懶加載 | 將不關鍵的資源延后加載。 | 定時器,事件觸發,可視區 |
預加載 | < link rel="preload" href="http://example.com" /> 動態加載,Ajax | |
預渲染 | < link rel="prerender" href="//yuchengkai.cn" /> | |
DNS預解析 | < link rel="dns-prefetch" href="//yuchengkai.cn" /> | |
服務器渲染 |
打開或關閉DNS預解析:
- 在服務器端發送 X-DNS-Prefetch-Control 報頭
- 在文檔中使用meta標簽:
<meta http-equiv="x-dns-prefetch-control" content="on">
在一些高級瀏覽器中,頁面中所有的超鏈接,默認打開了DNS預解析。
但是,如果頁面中采用的https協議,很多瀏覽器是默認關閉了超鏈接的DNS預解析。
如果加了上面這行代碼,則表明強制打開瀏覽器的預解析。
3.強緩存與協商緩存
強緩存
表示在緩存期間不需要請求,state code 為 200。
兩種響應頭實現: Expires 和 Cache-Control。
Expires: Wed, 22 Oct 2018 08:41:00 GMT
在指定的絕對時間后過期
Cache-control: max-age=30
30秒后過期
Cache-Control 出現於 HTTP / 1.1,優先級高於 Expires
協商緩存
向服務器確認緩存是否過期,配合強緩存,兩種實現方式。ETag 優先級比 Last-Modified 高。
(1)校驗修改時間: Last-Modified 和 If-Modified-Since
(2)校驗文件指紋: ETag 和 If-None-Match
首次請求資源,響應頭上會有Last-Modified或ETag。
再次請求時,請求頭上帶着If-Modified-Since、If-None-Match。
服務器進行校驗,如果資源沒變,響應304 Not Modifield,
改變了,則返回資源帶上新的Last-Modified或ETag。
如果在本地打開緩存文件,就會造成 Last-Modified 被修改,所以在 HTTP / 1.1 出現了 ETag 。
瀏覽器行為對緩存的影響
1)當ctrl+f5強制刷新網頁時,直接從服務器加載,跳過強緩存和協商緩存;
2)當f5刷新網頁時,跳過強緩存,但是會檢查協商緩存;
Cache-Control消息頭字段
在http 請求和響應中通過指定指令來實現緩存機制。緩存指令是單向的, 這意味着在請求設置的指令,在響應中不一定包含相同的指令。
* 禁止緩存
Cache-Control: no-cache, no-store, must-revalidate
* 緩存靜態資源
對於應用程序中不會改變的文件,你通常可以在發送響應頭前添加積極緩存。
對於頻繁變動的資源,可以使用 Cache-Control: no-cache 並配合 ETag 使用,表示該資源已被緩存,但是每次都會發送請求詢問資源是否更新。
對於代碼文件來說,通常使用 Cache-Control: max-age=31536000 並配合策略緩存使用,然后對文件進行指紋處理,一旦文件名變動就會立刻下載新的文件。
更多關於Cache-Control參考:MDN Cache-Control
更多關於緩存參考:MDN HTTP caching
4.使用 HTTP / 2.0
因為瀏覽器會有並發請求限制,在 HTTP / 1.1 時代,每個請求都需要建立和斷開,消耗了好幾個 RTT 時間,並且由於 TCP 慢啟動的原因,加載體積大的文件會需要更多的時間。
在 HTTP / 2.0 中引入了多路復用,能夠讓多個請求使用同一個 TCP 鏈接,極大的加快了網頁的加載速度。並且還支持 Header 壓縮,進一步的減少了請求的數據大小。
5.防抖和節流
debounce和throttle,
防抖和節流的作用都是防止函數多次調用。在事件和函數執行之間加了一個控制層。
防抖動是將多次執行變為最后一次執行,節流是將多次執行變成每隔一段時間執行。
指觸發事件后在 n 秒內函數只能執行一次,如果在 n 秒內又觸發了事件,則會重新計算函數執行時間。
/**
* @desc 函數防抖
* @param func 函數
* @param wait 延遲執行毫秒數
* @param immediate true 表立即執行,false 表非立即執行
*/
function debounce(func,wait,immediate) {
let timeout;
return function () {
let context = this;
let args = arguments;
if (timeout) clearTimeout(timeout);
if (immediate) {
var callNow = !timeout;
timeout = setTimeout(() => {
timeout = null;
}, wait)
if (callNow) func.apply(context, args)
}
else {
timeout = setTimeout(function(){
func.apply(context, args)
}, wait);
}
}
}
所謂節流,就是指連續觸發事件但是在 n 秒中只執行一次函數。
時間戳版和定時器版。
/**
* @desc 函數節流
* @param func 函數
* @param wait 延遲執行毫秒數
* @param type 1 表時間戳版,2 表定時器版
*/
function throttle(func, wait ,type) {
if(type===1){
let previous = 0;
}else if(type===2){
let timeout;
}
return function() {
let context = this;
let args = arguments;
if(type===1){
let now = Date.now();
if (now - previous > wait) {
func.apply(context, args);
previous = now;
}
}else if(type===2){
if (!timeout) {
timeout = setTimeout(() => {
timeout = null;
func.apply(context, args)
}, wait);
}
}
}