提綱:Web 性能優化沒有銀彈。簡單的靜態網頁得益於使用極少 JavaScript 代碼的服務端渲染。庫的謹慎使用能夠爲複雜的頁面帶來巨大的價值。javascript
Netflix 是最受歡迎的視頻流服務之一。自 2016 年在全球推出以來,公司發現許多新用戶不只經過移動設備完成註冊,並且還使用了不太理想的網絡鏈接。php
經過改進用於 Netflix.com 註冊過程 JavaScript 代碼和使用預加載技術,開發人員團隊能夠爲移動和桌面用戶提供更好的用戶體驗,並提供多項改進。前端
Netflix 開發者優化性能的地方是未登陸主頁,用戶在此頁面註冊並登陸站點。java
新用戶和已登出用戶的 Netflix.com 主頁react
此頁面初始包含 300KB 的 JavaScript 代碼,其中一些是 React 和其餘客戶端代碼(例如像 Lodash 的工具庫),並且還有一些是必要的上下文數據用來給 React 的狀態注水(hydrate)。android
全部 Netflix 的網頁都由服務端 React 渲染,這些頁面爲生成的 HTML 和客戶端應用提供服務,所以維持新優化的主頁結構不變和保持開發人員體驗的一致性一樣重要。ios
Homepage 選項卡是最初使用 React 編寫的組件的示例git
使用 Chrome 的 DevTools 和 Lighthouse 來模擬 3G 網絡下加載未登陸主頁,結果顯示未登陸主頁須要 7 秒時間來加載,這段時間對於一個簡單的入口頁面來講實在是過久了,因此咱們開始調查改進的可能性。經過一些性能審查,Netflix 發現他們的客戶端 JS 有太高的開銷。github
經過 Chrome DevTools 的網絡限速功能,查看未優化的 Netflix.com 的表現。web
經過關閉瀏覽器中的 JavaScript 來觀察站點中仍在起做用的元素,開發者團隊能夠決定 React 在未登陸主頁是否真正必要。
因爲頁面中的多數元素是基本的 HTML,剩下的元素好比 JavaScript 點擊處理和添加類能夠用原生 JavaScript 來替換,而頁面原來使用 React 實現的語言切換器則使用不到 300 行的原生 JavaScript 代碼重構。
移植到原生 JavaScript 的組件徹底列表:
雖然 React 的初始代碼僅僅 45 KB,在客戶端移除 React、一些庫和相應的 App 代碼減小的 JavaScript 代碼總量超多 200 KB,由此在 Netflix 的未登陸主頁下降了超過 50% 的可交互時間。
移除客戶端 React、Lodash 和其餘一些庫先後的負載比較。
在實驗環境下,咱們可使用 Lighthouse(trace)快速測驗用戶是否能與 Netflix 主頁交互。結果桌面端的 TTI 少於 3.5s。
可交互時間優化後的 Lighthouse 報告。
那麼這個領域的度量標準呢?使用 Chrome 用戶體驗報告咱們能夠看到首次輸入延遲 —— 從用戶首次與你的站點交互時間到瀏覽器真正響應那次交互的時間 —— 對於 97% 的 Netflix 桌面用戶來講很快。結果很是棒。
首先輸入延遲(FID)度量用戶在與頁面交互時的延遲體驗。
爲了進一步提升瀏覽登陸主頁的性能,Netflix 利用用戶在入口頁面上花費的時間針對可能會登陸的下一個頁面進行資源預加載。
經過兩項技術完成 —— 內置的 <link rel=prefetch>
瀏覽器 API 和 XHR 預加載。
內置的瀏覽器 API 包含頁面頭部標籤內的簡單連接標籤。它會建議瀏覽器資源(例如 HTML、JS、CSS、圖片)能夠被預加載,雖然它並不保證瀏覽器真的會預加載資源,而且它缺乏其餘瀏覽器的全面支持。
預加載技術對比
另外一方面,XHR 預加載已經成爲瀏覽器標準不少年了,當 Netflix 團隊提示瀏覽器緩存資源時,其成功率達到 95%。可是 XHR 預加載不能預加載 HTML 文檔,Netflix 用它來爲後續頁面預加載 JavaScript 和 CSS 打包文件。
注意:Netflix 配置的 HTTP 響應頭禁止使用 XHR 緩存 HTML(它們確實不緩存(no-cache)第二個頁面的 HTML)。連接預加載會按預期工做,由於它對 HTML 有效,即便設置了不緩存(no-cache)。
// 建立新的 XHR 請求
const xhrRequest = new XMLHttpRequest();
// open the request for the resource to "prefetch"
// 打開請求來「預加載」資源
xhrRequest.open('GET', '../bundle.js', true);
// 發送!
xhrRequest.send();
複製代碼
經過使用瀏覽器內置 API 和 XHR 預加載 HTML、CSS 和 JS,可交互時間減小了 30%。這個實現不須要重寫 JavaScript,也不會對未登陸主頁的性能形成負面影響,並且今後之後,能以極低的風險爲提高頁面性能提供了很是有價值的工具。
預加載實現以後,Netflix 開發者能夠經過分析頁面減小的可交互時間數據來觀察性能提高效果,一樣使用 Chrome 開發工具直接度量資源緩存的命中狀況。
經過預加載 Netflix 未登陸主頁資源和優化客戶端代碼,Netflix 能夠在註冊過程當中出色地提高可交互時間指標。經過使用瀏覽器內置 API 和 XHR 預加載來預獲取將來頁面,Netflix 能夠把可交互時間下降 30%。這是針對下一頁面的加載,其中包含單頁應用註冊過程的引導代碼。
Netflix 團隊進行的代碼優化代表,React 是一個十分有用的庫,不過它可能沒法爲每一個問題提供足夠的解決方案。經過從第一個用於註冊的入口頁面的客戶端代碼中刪除 React,可交互時間減小了 50% 以上。縮短客戶端上的可交互時間還可讓用戶以更快地速度單擊註冊按鈕,這代表代碼優化徹底能夠帶來更好的用戶體驗。
雖然 Netflix 沒有在主頁中使用 React,但他們爲後續的頁面預加載。這使得他們整個頁面應用程序流程中的其餘部分能夠利用客戶端 React。
更多關於這些優化的細節,請觀看 Tony Edwards 的出色演講:
經過密切關注 JavaScript 的開銷,Netflix 發現了改善可交互時間的機會。若想發現你的站點是否有機會在這點上作得更好,能夠藉助你的性能工具。
Netflix 決定作出的權衡是使用 React 對入口頁面進行服務器渲染,同時也在其上預先獲取 React 和其他註冊流程的代碼。這樣能夠優化首次加載性能,同時還能夠優化其他註冊流的加載時間,由於它是一個單頁應用程序,所以須要下載更大的 JS 打包文件。
考慮一下是否使用原生 JavaScript 是否適合你的站點的流程。若是你確實須要使用庫,那麼嘗試只嵌入你的用戶須要的代碼。預加載技術能夠幫助優化將來瀏覽頁面的加載時間。
感謝 Netflix UI 工程師,Tony Edwards、Ryan Burgess、Brian Holt、Jem Young、Kristofer Baxter(Google)、Nicole Sullivan(Chrome)和 Houssein Djirdeh(Chrome)的審閱和貢獻。
若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。
掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。