優化思路是什麼?
BIG QUESTION: 當我們談到一個web應用的性能優化,應該從哪些方面去考慮?
思路就是,當我們去訪問一個web應用的時候,都做了哪些操作?對應這些操作的,就是我們所能進行的優化的模塊!
- 瀏覽器請求DNS服務器,獲取IP地址;
- 建立TCP連接;
- 瀏覽器發出詳細請求,通常為HTTP(s)、WebSocket之類;
- 服務器響應請求,並返回數據;
- 瀏覽器渲染返回的數據到頁面;
- 釋放TCP連接;
那麼,我們接下來就按照這個流程,一步一步來看如何進行優化。
不好控制和不重要的優化內容
1. DNS
首先,DNS查詢的流程如下圖所示
當有瀏覽器緩存時,就不會去查詢之後的步驟,有無緩存的對比如下圖
可以看到,DNS Lookup這一步,在有緩存之後就不會出現。
2. TCP連接建立
同樣如上圖所示,Initial Connection 所佔用的時間即為TCP建立連接的耗時。由於TCP建立需要3次握手的操作,使其成為HTTP(s)協議通信耗時最長的過程。
針對這個過程,我們可以使用HTTP Keep-Alive機制,來保持TCP連接狀態,這樣可以使客户端不需要在每次http請求的時候都去與服務器建立TCP連接,可以節省掉很大的時間開支、提高服務器吞吐率。
之所以説這個也是不好控制和不重要的優化點,是因為現代瀏覽器已經默認支持 Keep-Alive,而常用的Web服務器也都可以對應進行支持。
如需手動設置,要注意 timeout 和 max 參數,保持時間太長的TCP連接,也會對服務器造成無用資源消耗。
重要的優化內容
3. 瀏覽器請求和服務器響應
針對請求和響應的優化,簡而言之,就是:
- 減少請求次數
- 降低請求耗時
在這裏,可做的優化點包括:
- CDN
- 壓縮傳輸,即GZIP/Deflate
- 前端模塊化
- 使用緩存
- 使用本地存儲
- 負載均衡:Nginx/SLB
3.1 CDN
CDN是Web應用優化的基礎,也是最重要最影響用户體驗的一個環節!
在項目中,需要注意將打包後的資源文件上傳到CDN地址,並且在構建工具中配置相關CDN信息。
3.2 數據壓縮
服務端與客户端的數據交互可通過壓縮來進行優化,常用的壓縮方式是 GZip和Deflate,本文以 GZip為例。
GZip支持 HTML/CSS/JS/XML/PlainText等多種格式的壓縮。
下圖可看出是否使用壓縮,對於傳輸文件大小的影響。
3.3 前端模塊化
前端模塊化便於文件管理、也更利於資源歸類壓縮,模塊化大致經歷瞭如下歷程。
script -> 閉包函數 -> AMD -> CMD -> CommonJS -> ES6
而對應的構建工具,也有以下發展歷程。
Grunt/Gulp -> Browserify -> Webpack
前端模塊化詳情可參見 《Web前端模塊化方法》
3.4 使用緩存
當客户端使用服務端返回的內容時,可以通過緩存機制,減少請求傳輸次數。
緩存分為 強制緩存和協商緩存 兩種。
強制緩存使用 Expires 和 Cache-Control:max-age 控制緩存有效時間。
協商緩存使用 Last-Modified 配合 ETag 控制緩存有效時間。
通常來講,系統優先匹配強制緩存。
對於靜態資源,系統需要做好相關緩存,避免重複請求。
3.5 使用本地存儲
使用本地存儲,可以在一定程度上減少服務器請求,也可以加快內容展示速度。
本地存儲的使用有以下歷程:
Cookie+變量 -> WebStorage -> 單頁面內存式存儲 -> IndexDB
變量 + Cookie
- Cookie 被設計來管理狀態,但在簡單應用中可存儲數據
- 4KB限制 + 域名綁定
單頁面內存式存儲
- 針對單頁面應用設計的變量存儲
- 如VueX
Web Storage
- LocalStorage & SessionStorage
- 區別:生命週期、作用域
IndexDB
- 終極方案、NoSQL
3.6 負載均衡
通常負載均衡包含4中模式:
4. 瀏覽器渲染
4.1 Async和Defer
對於資源文件的引入,使用 async和defer。
async 沒有固定順序,即加載到文件就會引入;
defer會按照dom順序進行插入。
4.2 懶加載
內容的懶加載,如配合 vue-router的按需加載;
圖片的懶加載,即需要展示時才去加載。
4.3 圖片優化
圖片優化是渲染層面能夠最大程度提升性能的優化模塊,也是操作起來最麻煩、需要投入精力最多的模塊。
筆者認為大致分為三個方向:
- 源:確保所有的圖片都從CDN源獲取
- 裁剪:使用正確大小的圖片
- 格式:按需使用格式
源和裁剪都比較明確,格式方面我們細説一下。
常用格式包括:
- JPG:
體積小、有損壓縮、不支持透明 - PNG:
體積大、無損壓縮、支持透明 - SVG:
文本文件、體積小、不失真、兼容性好 - BASE64:
文本文件、依賴編碼、小圖標解決方案;
需要少量小圖標時可以使用此方案,需要大量小圖標時建議使用CssSprites; -
WebP
新格式,支持動圖、體積小;瀏覽器支持的兼容性差。# 阿里在1688網站上的使用方法可以借鑑: https://alicdn.com/xxx.jpg_xxx.webp
4.4 Throttle & Debounce
節流(Throttle)
在某段時間內,不論觸發了多少次回調,都只做第一次,並在結束時給出響應。
防抖(Debounce)
在某段時間內,不論觸發了多少次回調,都只做最後一次,並在完成後給出響應。
節流和防抖的目標,都是減少執行,降低損耗,減少卡頓。
示例如下:
Throttle示例
let flag = false
window.onscroll = () => {
if (flag) {
return
}
flag = true
setTimeout(()=>{
doSomething()
flag = false
})
}
Debounce示例
<input onKeyUp="kp()">
var timer
var kp = ()=> {
clearTimeout(timer)
timer = setTimeout(()=> {
search()
}, 500)
}