[譯]Web 的現狀:網頁性能提升指南

原文:medium.com/@fox/talk-th

互聯網發展非常迅速,所以我們創造了Web平台。通常我們會忽視連通性等問題,但用戶們卻不會視而不見。一瞥萬維網的現狀,可以發現我們並沒有用同情心、變通意識去構建它,更不要說性能了。

所以,今天的Web是什麼狀態呢?

在這個星球上的74億人中,只有46%可以上網。平均網路速度上限為7Mb/s。更重要的是,有93%的互聯網用戶正在通過移動設備進行訪問——若不適配移動設備將引起用戶反感。通常情況下,數據比我們假設的更昂貴——可能需要1到13小時才能購買500MB的數據包(德國 vs. 巴西;更有趣的統計數據參見 Ben Schwarz 的 Beyond the Bubble: The Real World Performance)。

我們的網站也不是完美的——平均網站是原始Doom遊戲的大小(約3 MB)(請注意,為了統計準確,應使用中位數,閱讀 Ilya Grigorik 的優秀「平均頁面」是一個神話,中檔網站大小目前為1.4MB)。圖像可以輕鬆佔用1.7 MB的帶寬,而JavaScript平均值也有400KB的體積。這不僅是Web平台的問題,原生應用程序可能更糟,還記得為了獲取錯誤修復版本,而下載200MB安裝包的情景嗎?

技術人員經常會發現自己處於特權狀態。隨著最新的高端筆記本電腦、手機和快速有線互聯網連接,很容易讓我們忘記,這些並不是每個人都有的條件(實際上,真的很少)。

如果我們從特權和缺乏同情的角度來構建網路平台,那麼將導致排他性的糟糕體驗。

考慮到設計和開發的性能,我們怎樣才能做得更好?


優化所有資源

理解瀏覽器如何分析和處理資源,是顯著提高性能的最強大但未充分利用的方式之一。事實證明,瀏覽器在嗅探資源方面非常出色,同時解析並確定其優先順序。這裡是關鍵請求的來源。

如果請求中包含用戶視口中呈現內容所必需的資源,則該請求至關重要。

對於大多數網站,它將是HTML、必要的CSS、logo、網路字體,也可能是圖片。在許多情況下,幾十個其他不相關的資源(JavaScript、跟蹤代碼、廣告等)影響了關鍵請求。幸運的是,我們能夠通過仔細挑選重要資源並調整優先順序來控制這種行為。

通過 <link rel =preload> 我們可以手動強制調高資源的優先順序,確保所需的內容按時呈現。這種技術可以顯著改善「交互時間」指標,從而使最佳的用戶體驗成為可能。

關鍵請求對許多人來說,似乎仍然是一個黑匣子,可共享資料的缺乏並不能改變現狀。幸運的是,Ben Schwarz 發表了關於這個問題的非常全面並平易近人的文章——關鍵請求。另外,請參閱Addy的文章,在Chrome中的預載入、預取和優先順序(Preload, Prefetch and Priorities in Chrome)。

[在Chrome開發人員工具中啟用優先順序]

要跟蹤在請求優先順序處理方面的情況,請使用Lighthouse性能工具和關鍵請求鏈審核工具,或查看Chrome開發人員工具中「網路」選項卡下的請求優先順序。

通用性能清單

  1. 積極地緩存
  2. 啟用壓縮
  3. 優化關鍵資源的優先順序
  4. 使用CDN(Content Delivery Networks)

圖片優化

圖片通常佔網頁傳輸的大部分有效載荷,因此圖片優化可以帶來最大的性能提升。有許多現有的策略和工具可以幫助我們刪除額外的位元組,但是首先應考慮的問題是:「圖片對於我想傳達的信息和效果至關重要嗎?」。如果可以消除它,不僅可以節省帶寬,而且還節省了請求。

在某些情況下,可以通過不同的技術實現類似的結果。比如CSS就具有藝術方向的一系列屬性,例如陰影、漸變、動畫及形狀,允許我們構造適當風格的DOM元素。

選擇正確的格式

如果不能捨棄圖片,確定哪種格式更合適就很重要了。首先要在矢量和光柵圖形之間做出選擇:

  • 矢量圖形:解析度獨立,通常體積更小。非常適合logo、icon和簡單的圖形,包括基本形狀(線,多邊形,圓和點)。
  • 光柵圖形:呈現更詳細的信息,比較適合相片。

做出首個決定後,可以選擇以下幾種格式:JPEG、GIF、PNG–8、PNG–24,或最新的 WEBP 與 JPEG-XR 格式。有了這麼多的選項,如何確保我們做出正確的選擇?以下是找出最佳格式的基本方法:

  • JPEG:顏色非常豐富的圖片(例如照片)
  • PNG–8:色彩相對單一的圖片
  • PNG–24:局部透明的圖片
  • GIF:動圖

Photoshop可以通過各種設置,例如降低質量、降低噪音或色彩數量來優化以上每一種格式。確保設計師了解上述性能實踐,並能夠使用正確的方式優化相應格式的圖片。如果您想了解更多如何處理圖片,請閱讀 Lara Hogan 的好文 Designing for Performance。

試用新格式

圖像格式有幾個較新的玩家,即WebP、JPEG 2000 和 JPEG-XR。它們都是由瀏覽器廠商開發的:Google 的 WebP,Apple 的 JPEG 2000 和 Microsoft 的 JPEG-XR。

WebP 是最受歡迎的競爭者,支持無損和有損壓縮,這使得它非常靈活。無損的 WebP 比 PNG 小26%,比 JPG 小25-34%。WebP 有著74%的瀏覽器支持,它可以安全地進行降級,最多可節省1/3的傳輸位元組。JPG 和 PNG 可以在 Photoshop 和其他圖像處理應用程序以及命令行界面(brew install webp)中轉換為WebP。

如果你想探索其他格式之間的視覺差異,推薦 Github 上這個很贊的 Demo。

用工具和演算法進行優化

即使使用了高效的圖像格式,也不應跳過後處理優化。這一步很重要。

如果您選擇了尺寸相對較小的 SVG,它們也是可以再次壓縮的。SVGO 是一個命令行工具,可以通過剝離不必要的元數據來快速優化 SVG。另外,如果您喜歡Web界面或受操作系統的限制,請使用 Jake Archibald 的 SVGOMG。因為 SVG 是基於 XML 的格式,它也可以在伺服器端進行 GZIP 壓縮。

ImageOptim 是大多其他圖像類型的最好選擇。包括 pngcrush、pngquant、MozJPEG、Google Zopfli等,它在一個全面的開源包中捆綁了一大堆優秀的工具。ImageOptim 可以以 Mac OS 應用程序、命令行界面和 Sketch 插件形式,輕鬆地實現到現有的工作流程中。對於那些在 Linux 或 Windows 上的場景,大多數 ImageOptim 的 CLI 都可以在您的平台上使用。

如果您傾向於嘗試新興的編碼器,Google 今年早些時候發布了 Guetzli——源自 WebP 和 Zopfli 的開源演算法。Guetzli 可以比任何其他可用的壓縮方法生成35%更小體積的 JPEG。唯一的缺點是:處理時間慢(CPU 每處理百萬像素需要1分鐘)。

選擇工具時,請確保它們生成所需的結果並適應團隊的工作流程。理想情況是,將優化過程自動化,這樣就不會產生漏掉的情況。

響應式圖片

十年前,我們使用一種解析度,就可以為所有人服務,但時代變化太快,現今的響應式 Web 已非往日可比。這也是為什麼我們必須要特別留心,去精心優化視覺資源,確保它們適應各種視口設備。幸運的是,感謝 Responsive Images 社區小組,我們可以完美使用 picture 元素和 srcset 屬性(二者都有85%+支持率)。

srcset 屬性

srcset在解析度切換方案中效果最佳——即當我們需要根據用戶的屏幕密度和大小顯示圖像時。基於srcset和size屬性中的一組預定義規則,瀏覽器將選擇最佳圖片,相應地提供給視口。這項技術可以帶來很大的帶寬和請求節省,特別是對於移動用戶。

[srcset 使用示例]

picture 元素

picture元素和media屬性旨在使藝術設計變得容易。通過為不同情形提供不同圖片(通過媒體查詢進行測試),無論什麼解析度,我們都能始終將圖像中最重要的元素保持在焦點。

[picture 元素使用示例]

請務必閱讀 Jason Grigsby 的 Responsive Images 101指南,以便對這兩種方法進行徹底的闡述。

使用圖片 CDN 進行分發

視覺優化的最後一步是分發。所有資源都可以從使用 內容分發網路 中受益,但還有一些針對圖片優化的特定工具,例如 Cloudinary 和 imgx。使用這些服務的好處遠遠超過了減少伺服器上的流量,並顯著降低了響應延遲。

CDN可以很好的解決重圖片網站的複雜度,包括響應式服務與圖片優化。雖然產品不同(價格也是如此),但是大多數方案都是根據設備和瀏覽器,調整大小、裁剪來確定哪種格式最適合用戶。甚至更多——它們可以壓縮、檢測像素密度、水印、識別面部,並允許後置處理能力。藉助這些強大的功能,和將參數附加到URL的能力,以用戶為中心的圖片服務變得十分容易。

圖像性能清單

  1. 選擇正確的圖片格式
  2. 儘可能使用矢量圖形
  3. 如果變化不明顯,則降低圖片質量
  4. 使用新格式圖片
  5. 使用工具與演算法優化
  6. 學習srcset和picture
  7. 使用圖片 CDN

Web 字體優化

自定義字體是一項非常強大的設計工具。但是能力伴隨著很多責任。現有68%的網站在使用 Web字體,這種類型的資源是性能殺手之一(平均輕鬆可達100KB,取決於變體和字體的數量)。

即使體積不是最大的問題,不可見文本閃動(FOIT)也算是。當Web字體載入中或載入失敗時,會發生FOIT,這會讓空白頁面,從而導致內容無法訪問。首先仔細檢查我們是否需要Web字體可能是值得的。如果真是這樣,有一些策略可以幫助我們減輕對業務的負面影響。

選擇正確的格式

有4種網路字體格式:EOT、TTF、WOFF 和最近的 WOFF2。TTF 和 WOFF 被廣泛使用,擁有超過90%的瀏覽器支持率。根據支持情況,最有可能安全地使用WOFF2,並在舊版瀏覽器降級使用 WOFF。使用WOFF2的優點是,一套定製的預處理和壓縮演算法(如Brotli),並有大約30%的文件大小減少和改進的解析能力。

在@font-face中定義網頁字體的來源時,請使用format()提示來指定應使用哪種格式。

如果您使用 Google Fonts 或 Typekit 來提供字體,這兩種工具都實施了一些策略來優化其性能。Typekit 現在可以非同步地為所有套件提供服務,防止 FOIT 以及允許其JavaScript套件代碼的10天延長緩存期限(而不是默認10分鐘)。Google Fonts 可以根據用戶設備自動提供最小的文件。

審核字體範圍

無論是否自主託管,字體數量、字體體積和樣式,都將顯著影響您的性能預算。

理想情況下,我們只需要一種包括常規和粗體的字體。如果您不確定如何選擇字體範圍,請參考 Lara Hogan 的 Weighing Aesthetics and Performance。

使用Unicode範圍子集

Unicode範圍子集允許將大字體分割成較小的集合。這是一個相對先進的策略,特別是在處理亞洲語言的時候,可能會帶來顯著的節省(你知道中文字體有平均數為 20,000 個字形嗎?)。第一步是將字體限制為必要的語言集,例如拉丁語,希臘語或西里爾語。如果僅使用Web字體做Logo類使用,則應使用Unicode範圍描述符,來選擇特定字元。

Filament Group 發布了一個開源命令行工具,可以根據文件或URL生成必要字形列表的 glyph hanger。或者,基於 Web 的 Font Squirrel Web Font Generator 提供高級子集和優化選項。如果在字體選擇器界面中內置了使用Google Fonts 或 Typekit 選擇語言子集,則使基本子集更容易。

建立字體載入策略

字體是阻塞渲染的——因為瀏覽器必須首先構建 DOM 和 CSSOM;在使用與現有節點相匹配的CSS選擇器之前,瀏覽器並不會下載Web字體。這種行為會明顯延遲文本呈現,通常會導致前面提到的不可見文本閃動(FOIT)。在較慢的網路和移動設備上,FOIT會更加顯著。

實施字體載入策略,可防止用戶無法訪問您的內容。通常,選擇無樣式文本閃動(FOUT)是最簡單和最有效的解決方案。

font-display是提供非 JavaScript 依賴解決方案的新 CSS 屬性。不幸的是,它僅有部分支持(Chrome 和 Opera),目前正在 Firefox 和 WebKit 中開發。儘管如此,它可以並且應該與其他字體載入機制結合使用。

[font-display 屬性實踐]

幸運的是,Typekit 的 Web Font Loader 和 Bram Stein 的 Font Face Observer 可以幫助管理字體載入行為。此外,網頁字體性能專家 Zach Leatherman 發布了字體載入策略綜合指南,這將有助於為您的項目選擇正確的方法。

字體性能清單

  1. 選擇正確的格式
  2. 審核字體範圍
  3. 使用Unicode範圍子集
  4. 建立字體載入策略

JavaScript 優化

目前,JavaScript 的平均大小為446 KB,已經使其成為第二大的資源類型(第一為圖片)。

我們可能沒有意識到,我們所愛的JavaScript隱藏著更加嚴峻的性能瓶頸。

監控JavaScript的流量

優化交付只是解決網頁膨脹的第一步。JavaScript 下載後,必須由瀏覽器進行解析、編譯和運行。快速瀏覽一些流行的網站,顯而易見的是,gzip 壓縮的 JS 在解壓之後至少變大三倍。事實上,我們正在發送一大堆代碼。

1MB JavaScript 在不同設備上的解析時間。圖片由 Addy Osmani 和他的 JavaScript Start-up Performance 文章提供。

分析解析和編譯時間,對於理解應用程序是否準備好進行交互至關重要。這些耗時根據用戶設備的硬體能力而異。解析和編譯會很容易在低端手機上高出2-5倍。Addy的研究證實,在常規手機上,一個應用程序將需要16秒才能達到互動式狀態,而在桌面電腦上為8秒。分析這些指標至關重要,幸運的是,我們可以通過 Chrome DevTools 來完成。

[在 Chrome 開發工具中查看解析和編譯過程]

請務必閱讀 Addy Osmani 對 JavaScript 啟動性能的詳細說明。

擺脫不必要的依賴

現代軟體包管理器的工作方式,可以輕而易舉地掩蓋依賴關係的數量和大小。webpack-bundle-analyzer 和 Bundle Buddy 是很好的可視化工具,幫助識別出代碼重複、最大性能問題和過時的、不必要的依賴。

圖 webpack bundle analyzer 實踐(譯者註:原gif太大,只能用外鏈了)

通過 VS Code 和 Atom 中的Import Cost擴展,我們可以使導入依賴成本更加明顯。

圖 VS Code Import Code擴展

實現代碼分割

只要有可能,我們就應只提供用戶體驗所必需的資源。向用戶發送一個完整的

bundle.js 文件,包括他們可能永遠看不到的交互效果處理代碼,並不太理想(假設在訪問著陸頁時,去下載處理整個應用程序的 JavaScript)。同樣,我們不應普遍提供針對特定瀏覽器或用戶代理的代碼。

Webpack,最受歡迎的模塊打包器之一,天生具備代碼分割支持。最簡單的代碼分割可以按頁面實現(如用於著陸頁的home.js,聯繫人頁面的contact.js等),Webpack 還提供了一些高級策略,如動態導入及延遲載入,值得一看。

考慮框架選擇

JavaScript 前端框架日新月異。根據2016年的 JavaScript 調查,React 是最受歡迎的選擇。仔細審視架構選擇,可能會發現,您可以使用更為輕量級的替代方案,例如 Preact(請注意,Preact 並不是一個完整的 React 重新實現,只是一個高性能,功能更輕的虛擬 DOM 庫)。類似地,我們可以將較大的庫更換成更小的版本——moment.js換成date-fns(或者在特定情況, href="github.com/distilagency">刪除moment.js中未使用的 locales)。

在開始一個新項目之前,有必要確定什麼樣的功能是必需的,並為您的需求和目標選擇最具性能的框架。有時這可能意味著選擇寫更多的原生 JavaScript。

JavaScript 性能清單

  1. 監控 JavaScript 流量
  2. 擺脫不必要的依賴
  3. 實現代碼分割
  4. 考慮框架選擇

性能追蹤,前進之路

我們已經討論了一些策略,在大多數情況下會對我們正在建立的產品用戶體驗產生積極的變化。性能可能是一個棘手的問題,有必要長期地跟蹤我們調整的結果。

以用戶為中心的性能指標

卓越的性能指標,旨在儘可能接近描繪用戶體驗。以往的onLoad,onContentLoaded或SpeedIndex對「用戶多快能與頁面交互」給出的信息非常少。當聚焦到傳輸資源時,量化地感知性能十分困難。好在,有一些時間可以全面地描述內容的可視性和互動性。

這些指標是首次渲染(First Paint),首次有意義渲染(First Meaningful Paint),視覺完整(Visually Complete)和可交互時間(Time to Interactive)。

  • 首次渲染:瀏覽器從白色屏幕到第一次視覺呈現的變化。
  • 首次有意義渲染:文字,圖像和主要內容都已可見。
  • 視覺完整:視口中的所有內容都可見。
  • 可交互時間:視口中的所有內容都是可見的,可以與之進行交互(JavaScript 主線程停止活動)。

這些時間直接對應於用戶的實際體驗,因此可以作為重點進行追蹤。如果可能,將它們記錄全部,否則選擇一兩個來更好地監控性能。其他指標也需要留意,特別是我們發送的位元組數(優化和解壓縮)。

設置性能預算

所有這些上報數字可能會很快變得混亂和不易理解。沒有可操作的目標和對象,很容易迷失我們最初的目的。幾年前,Tim Kadlec 寫過關於性能預算的概念。

遺憾的是,並沒有一個萬能的神奇公式。性能預算通常歸結為競爭分析和產品目標,而這是每個業務所各異的。

設定預算時,重要的是要達到明顯的差異,通常是至少改善20%。實踐和迭代您的預算,利用 Lara Hogan 的方法新設計與性能預算作為參考。

試用性能預算計算器或Chrome擴展瀏覽器卡路里,以幫助創建預算。

持續監控

監控性能不應該是手動的。市面上有很多強大的工具,還可以提供全面的報告。

Google Lighthouse 是一個可以審核性能、可訪問性、漸進式網路應用程序等的開源項目。您可以在命令行中或直接在 Chrome Developer Tools 中使用Lighthouse。

[Lighthouse 運行一次性能審查]

對於持續的追蹤,選擇選擇 Calibre,它可以提供性能預算、設備模擬、分散式監控和許多其他功能,無需我們仔細構建自己的性能套件即可獲得。

[Calibre 報表]

無論您在追蹤什麼,請確保使整個團隊或組織能夠透明地訪問數據。

性能是一項分擔責任,遠遠超過開發人員團隊——我們都應對所創建的用戶體驗負責,不管是什麼角色或職級。

倡導速度和建立協作流程,以便在產品決策或設計早期階段,儘早暴露可能遇到的瓶頸,是非常重要的。

建立性能意識和同情心

關心性能不僅僅是一個業務目標(但是如果您需要通過銷售統計數據來進行銷售,那麼可以通過PWA統計)。這是關於基本的同情和用戶體驗放在第一位。

作為技術專家,我們的責任是,不要讓用戶的注意力和時間放在等待頁面上,而已可以更開心地花費在其他地方。我們的目標是建立意識到時間和人們關注的工具。

提倡性能意識應該是每個人的目標。讓我們抱著性能和同情心,為大家建立一個更好、更有意義的未來吧。


推薦閱讀:

node.js-腳本合併

TAG:前端性能優化 |