- 原文地址:Front-End Performance Checklist 2018 - Part 3
- 原文作者:Vitaly Friedman
- 譯文出自:掘金翻譯計劃
- 本文永久連結:github.com/xitu/gold-m…
- 譯者:Cherry
- 校對者:Ryou、z
下面你將會看到你可能需要考慮到的前端效能優化問題,以保證你的應用具有快速和流暢的響應時間。
靜態資源優化
- 你是使用 Brotli 還是 Zopfli 進行純文字壓縮?
在 2005 年,Google 推出了 Brotli,一個新的開源無損資料壓縮格式,現在 被所有的現代瀏覽器所支援。實際上,Brotli 比 Gzip 和 Deflate 更有效。取決於設定資訊,壓縮可能會非常慢。但是緩慢的壓縮過程會提高壓縮率,並且仍然可以快速解壓。當然,解壓縮速度很快。
只有當使用者通過 HTTPS 訪問網站時,瀏覽器才會採用。Brotli 現在還不能預裝在某些伺服器上,而且如果不自己構建 NGINX 和 UBUNTU 的話很難部署。不過這也並不難。實際上,一些 CDN 是支援的,甚至 可以也可以通過伺服器在不支援 CDN 的情況下啟用 Brotli。
在最高階別的壓縮下,Brotli 的速度會變得非常慢,以至於伺服器在等待動態壓縮資源時開始傳送響應所花費的時間可能會使檔案大小的任何潛在收益都無效。但是,對於靜態壓縮,高壓縮比的設定比較受歡迎 —— (感謝 Jeremy!)
或者,你可以考慮使用 Zopfli 的壓縮演算法,將資料編碼為 Deflate,Gzip 和 Zlib 格式。Zopfli 改進的 Deflate 編碼使得任何使用 Gzip 壓縮的檔案受益,因為這些檔案大小比 用Zlib 最強壓縮後還要小 3% 到 8%。問題在於壓縮檔案的時間是原來的大約 80倍。這就是為什麼雖然 使用 Zopfli 是一個好主意但是變化並不大,檔案都需要設計為只壓縮一次可以多次下載的。
比較好的方法是你可以繞過動態壓縮靜態資源的成本。Brotli 和 Zopfli 都可以用於明文傳輸 —— HTML,CSS,SVG,JavaScript 等。
有什麼方法呢?在最高等級和 Brotli 的 1-4 級動態壓縮 HTML 使用 Brotli+Gzip 預壓縮靜態資源。同時,檢查 Brotli 是否支援 CDN,(例如 KeyCDN,CDN77,Fastly)。確保伺服器能夠使用 Brotli 或 gzip 處理內容。如果你不能安裝或者維護伺服器上的 Brotli,那麼請使用 Zopfli。
- 影像是否進行了適當的優化?
儘可能通過
srcset
,sizes
和<picture>
元素使用 響應式圖片。也可以通過<picture>
元素使用 WebP 格式的影像(Chrom,Opera,Firefox soon支援),或者一個 JPEG 的回撥(見 Andreas Bovens 的 code snippet)或者通過使用內容協商(使用Accept
頭資訊)。
Sketch 本身就支援 WebP 並且 WebP 影像可以通過使用 WebP 外掛 從 PhotoShop 中匯出。也有其他選擇可以使用,如果你使用 WordPress 或者 Joomla,也有可以輕鬆支援 WebP 的擴充套件,例如 Optimus 和 Cache Enabler(通過 Cody Arsenault)
你可以仍然使用 client hints,但仍需要獲得一些瀏覽器支援。沒有足夠的資源支援響應式圖片?使用 斷點發生器 或者類似 Cloudinary 這樣的服務自動優化圖片。同樣,在許多情況下,只使用 srcset
和 sizes
會有不錯的效果。
On Smashing Magazine, we use the postfix -opt
for image names — for example, brotli-compression-opt.png
; whenever an image contains that postfix, everybody on the team knows that the image has already been optimized.
響應影像斷點生成器自動生成影像和標記生成。
- 將影像優化到下一個級別 現在有一個至關重要著陸頁,有一個特定的圖片的載入速度非常關鍵,確保 JPEGs 是漸進式的並且使用 Adept、 mozJPEG (通過操縱掃描級來改善開始渲染時間)或者 Guetzli 壓縮,谷歌新的開源編碼器重點是能夠感官的效能,並借鑑 Zopfli 和 WebP。唯一的 不足 是:處理的時間慢(每百萬畫素 CPU 一分鐘)。至於 png,我們可以使用 Pingo,和 svgo,對於 SVG 的處理,我們使用 SVGO 或 SVGOMG
每一個影像優化的文章會說明,但始終保持保持向量資產清潔總是值得提醒的。確保清理未使用的資源,刪除不必要的後設資料,並減少圖稿中的路徑點數量(從而減少SVG程式碼)。(感謝,Jeremy!)
到目前為止,這些優化只涵蓋了基礎知識。 Addy Osmani 已經發布了 一個非常詳細的基本影像優化指南,深入到影像壓縮和顏色管理的細節。 例如,您可以模糊影像中不必要的部分(通過對其應用高斯模糊濾鏡)以減小檔案大小,最終甚至可以開始移除顏色或將影像變成黑白色,以進一步縮小影像尺寸。 對於背景影像, 從Photoshop 匯出的照片質量為 0 到 10% 也是絕對可以接受的。
那麼 GIF 圖片呢?我們可以使用 迴圈的 HTML5 視訊,而不是影響渲染效能和頻寬的重度 GIF 動畫,而使用迴圈的 HTML5 視訊,<video>
會使得 瀏覽器的效能很慢,而且與影像不同的是,瀏覽器不會預先載入 <video>
內容。 至少我們可以使用 Lossy GIF, gifsicle 或者 giflossy 新增有失真壓縮 GIF。
好 訊息: 希望不久以後我們可以使用 <img src=".mp4">
來載入視訊, 早期的測試表明 img
標籤比同等大小的 GIF 顯示的要 快 20 多倍解析速度與要快 7 倍多。
還不夠好?那麼,你也可以使用 多種 背景 影像 技術 提高影像的感知效能。 記著,減少對比度 和模糊不必要的細節(或消除顏色)也可以減小檔案的大小。 你需要放大一個小照片而不失真?考慮使用 Letsenhance.io
Zach Leatherman 的 字型載入策略綜合指南 提供了十幾種更好的網頁字型傳送選項
- Web字型是否優化? 首先需要問一個問題,你是否能不使用 UI 系統字型。 如果不可以,那麼你有很大可能使用 Web 網路字型,會包含字形和額外的功能以及用不到的加粗。 如果您使用的是開源字型(例如,通過僅包含帶有某些特殊的重音字形的拉丁語),則可以只選擇部分 Web 字型來減少其檔案大小。
WOFF2 非常好,你可以使用 WOFF 和 OTF 作為不支援它的瀏覽器的備選。另外,從 Zach Leatherman 的《字型載入策略綜合指南》(程式碼片段也可以作為 Web字型載入片段)中選擇一種策略,並使用伺服器快取持久地快取字型。是不是感覺小有成就?Pixel Ambacht 有一個 快速教程和案例研究,讓你的字型按順序排列。
如果你無法從你的伺服器拿到字型並依賴於第三方主機,請確保使用 字型載入事件(或對不支援它的瀏覽器使用 Web字型載入器)FOUT 要優於 FOIT; 立即開始渲染文字,並非同步載入字型 —— 也可以使用 loadCSS。 你也可以 擺脫本地安裝的作業系統字型,也可以使用 可變的 字型。
怎麼才能是一個無漏洞的字型載入策略? 從 font-display
開始,然後回到 Font Loading API,然後回到 Bram Stein 的 Font Face Observer(感謝 Jeremy!)如果你有興趣從使用者的角度來衡量字型載入的效能, Andreas Marschke 探索了 使用 Font API 和 UserTiming API 進行效能跟蹤
此外,不要忘記包含 font-display:optional
描述符來提供彈性和快速的字型回退,unicode-range
將大字型分解成更小的語言特定的字型,以及Monica Dinculescu 的字型樣式匹配器 用來解決由於兩種字型之間的大小差異,最大限度地減少了佈局上的震動的問題。
交付優化
- 你是否非同步載入 JavaScript?
當使用者請求頁面時,瀏覽器獲取 HTML 並構造 DOM,然後獲取 CSS 並構造 CSSOM,然後通過匹配 DOM 和 CSSOM 生成一個渲染樹。如果有任何的 JavaScript 需要解決,瀏覽器將不會開始渲染頁面,直到 JavaScript 解決完畢,這樣就會延遲渲染。 作為開發人員,我們必須明確告訴瀏覽器不要等待並立即開始渲染頁面。 為指令碼執行此操作的方法是使用 HTML 中的
defer
和async
屬性。
事實證明,我們 應該把 defer
改為 async
(因為 ie9 及以下不支援 async)。 另外,如上所述,限制第三方庫和指令碼的影響,特別是使用社交共享按鈕和嵌入的 <iframe>
嵌入(如地圖)。 大小限制 有助於防止 JavaScript 庫過大:如果您不小心新增了大量依賴項,該工具將通知你並丟擲錯誤。 您可以使用 靜態社交分享按鈕(如通過 SSBG )和 靜態連結 來代替互動式地圖。
- 你是否懶載入了開銷很大並使用 Intersection Observer 的程式碼? 如果您需要延遲載入圖片、視訊、廣告指令碼、A/B 測試指令碼或任何其他資源,則可以使用 Intersection Observer API,它提供了一種方法非同步觀察目標元素與 祖先元素或頂層文件的視口。基本上,你需要建立一個新的 IntersectionObserver 物件,它接收一個回撥函式和一組選項。 然後我們新增一個目標來觀察。
當目標變得可見或不可見時執行回撥函式,所以當它攔截視口時,可以在元素變得可見之前開始採取一些行動。 事實上,我們可以精確地控制觀察者的回撥何時被呼叫,使用 rootMargin
(根邊緣)和 threshold
(一個數字或者一個數字陣列來表示目標可見度的百分比, 瞄準)。Alejandro Garcia Anglada 發表了一個 簡單的教程 關於如何實際實施的方便教程。
你甚至可以通過向你的網頁新增 漸進式圖片載入 來將其提升到新的水平。 與 Facebook,Pinterest 和 Medium 類似,你可以首先載入低質量或模糊的影像,然後在頁面繼續載入時,使用 Guy Podjarny 提出的 LQIP (Low Quality Image Placeholders) technique(低質量影像佔位符)技術替換它們的全部質量版本。
如果技術提高了使用者體驗,觀點就不一樣了,但它肯定會提高第一次有意義的繪畫的時間。我們甚至可以通過使用 SQIP 建立影像的低質量版本作為 SVG 佔位符來實現自動化。 這些佔位符可以嵌入 HTML 中,因為它們自然可以用文字壓縮方法壓縮。 Dean Hume 在他的文章中 描述了 如何使用相交觀測器來實現這種技術。
瀏覽器支援成都如何呢?Decent,與 Chrome,火狐,Edge 和 Samsung Internet 已經支援了。 WebKit 目前 正在開發中。如果瀏覽器不支援呢? 如果不支援交叉點觀察者,我們仍然可以 延遲載入 一個 polyfill 或立即載入影像。甚至還有一個 library。
通常,我們會使用懶載入來處理所有代價較大的元件,如 字型,JavaScript,輪播,視訊和 iframe。 你甚至可以根據網路質量調整內容服務。網路資訊 API,特別是 navigator.connection.effectiveType
(Chrome 62+)使用 RTT 和下行鏈路值來更準確地表示連線和使用者可以處理的資料。 您可以使用它來完全刪除視訊自動播放,背景圖片或 Web 字型,以便連線速度太慢。
- 你是否優先載入關鍵的 CSS?
為確保瀏覽器儘快開始渲染頁面,通常 會收集開始渲染頁面的第一個可見部分所需的所有 CSS(稱為 “關鍵CSS” 或 “上一層CSS”)並將其內聯新增到頁面的
<head>
中,從而減少往返。 由於在慢啟動階段交換包的大小有限,所以關鍵 CSS 的預算大約是 14 KB。
如果超出這個範圍,瀏覽器將需要額外往返取得更多樣式。 CriticalCSS 和 Critical 可以做到這一點。 你可能需要為你使用的每個模板執行此操作。 如果可能的話,考慮使用 Filament Group 使用的 條件內聯方法。
使用 HTTP/2,關鍵 CSS 可以儲存在一個單獨的 CSS 檔案中,並通過 伺服器推送 來傳遞,而不會增大 HTML 的大小。 問題在於,伺服器推送是很 麻煩,因為瀏覽器中存在許多問題和競爭條件。 它一直不被支援,並有一些快取問題(參見 [Hooman Beheshti介紹的文章](Hooman Beheshti's presentation) 114 頁內容)。事實上,這種影響可能是 負面的,會使網路緩衝區膨脹,從而阻止文件中的真實幀被傳送。 而且,由於 TCP 啟動緩慢,似乎伺服器推送在熱連線上 更加有效。
即使使用 HTTP/1,將關鍵 CSS 放在根目錄上的單獨檔案中也是有 好處的,有時甚至比快取和內聯更為有效。 Chrome 請求這個頁面的時候會再傳送一個 HTTP 連線到根目錄,從而不需要 TCP 連線來獲取這個 CSS(感謝 Philip!)
需要注意的一點是:和 preload
不同的是,preload
可以觸發來自任何域的預載入,而你只能從你自己的域或你所授權的域中推送資源。 一旦伺服器得到來自客戶端的第一個請求,就可以啟動它。 伺服器將資源壓入 Push 快取,並在連線終止時被刪除。 但是,由於可以在多個選項卡之間重複使用 HTTP/2 連線,所以推送的資源也可以被來自其他選項卡的請求宣告(感謝 Inian!)。
目前,伺服器並沒有一個簡答的方法得知被推送的資源 是否已經存在於使用者的快取中,因此每個使用者的訪問都會繼續推送資源。因此,您可能需要建立一個 快取監測 HTTP/2 伺服器推送機制。如果被提取,您可以嘗試從快取中獲取它們,這樣可以避免再次推送。
但請記住,新的 cache-digest
規範 無需手動建立這樣的 “快取感知” 的伺服器,基本上在 HTTP/2 中宣告的一個新的幀型別就可以表達該主機的內容。因此,它對於 CDN 也是特別有用的。
對於動態內容,當伺服器需要一些時間來生成響應時,瀏覽器無法發出任何請求,因為它不知道頁面可能引用的任何子資源。 在這種情況下,我們可以預熱連線並增加 TCP 擁塞視窗大小,以便將來的請求可以更快地完成。 而且,所有內聯配置對於伺服器推送都是較好的選擇。事實上,Inian Parameshwaran 對 HTTP/2 Push 和 HTTP Preload 進行了比較 深入的研究,內容很不錯,其中包含了您可能需要的所有細節。伺服器到底是推送還是不推送呢?你可以閱讀一下 Colin Bendell 的 Should I Push?。
底線:正如 Sam Saccone 所說,preload
有利於將資產的開始下載時間更接近初始請求, 而伺服器推送是一個完整的 RTT(或 更多,這取決於您的伺服器反應時間 —— 如果你有一個伺服器可以防止不必要的推送。