輕鬆實現 Web 效能優化
原文作者:Addy Osmani
譯者:UC 國際研發 Jothy
寫在最前:歡迎你來到“UC國際技術”公眾號,我們將為大家提供與客戶端、服務端、演算法、測試、資料、前端等相關的高質量技術文章,不限於原創與翻譯。
這是一篇關於效能優化的文章,是一篇非常值得你閱讀的文章,文章的內容非常豐富,大概你花5-10分鐘閱讀。
在過去的一年裡,我們忙於試圖弄清楚如何讓網路更快、更高效。因此就有了我們希望在本文中與你分享的新工具,方法和庫。在第一部分中,我們將向你展示我們在開發 The Oodles Theater App 時使用的一些優化技術。在第二部分中,我們將討論我們的預測載入實驗和新的 Guess.js 計劃。
Tip:你可以在 Youtube 觀看視訊 https://www.youtube.com/watch?v=Mv-l3-tJgGk
效能的需要
網際網路每年都在變得越來越重。如果我們檢查網頁的狀態,我們可以看到一箇中等大小的移動端頁面大約為 1.5MB,其中大部分是 JavaScript 和圖片。
網站規模不斷擴大,加上其他因素,如網路延遲,CPU 限制,渲染阻塞模式或多餘的第三方程式碼,都會導致複雜的效能難題。
大多數使用者把速度當成使用者體驗需要層次理論(User Experience Hierarchy of Needs,見下圖)的最高層。這並不太令人驚訝,因為在頁面載入完成之前,你有很多事情都做不了。你無法從頁面中獲取價值,你無法欣賞它的美學。
圖1. 速度對使用者有多重要?
我們知道效能對使用者很重要,但它又像是一個尋找從哪裡開始優化的祕密。幸好有一些工具可以幫助我們。
Lighthouse ——效能工作流的基礎
Lighthouse 屬於 Chrome DevTools 的一部分,它允許你對你的網站進行審查,並提供優化建議。
我們最近推出了一系列新的效能審查(https://developers.google.com/web/updates/2018/05/lighthouse),它們在日常開發工作流中非常有用。
圖2. 新 Lighthouse 審查
讓我們來探索一下如何在一個實際的例子中利用它們:Oodles Theatre App。這是一個小型的 demo web app,你可以在裡面試用我們最愛的一些互動式 Google Doodle,甚至玩一兩局遊戲。
在構建 App 時,我們希望確保它儘可能高效。優化的起點是 Lighthouse 報告。
圖3. Oodles App 的 Lighthouse 報告
我們的 App 在 Lighthouse 報告中的初始表現非常糟糕。使用 3G 網路時,使用者需要等待 15 秒才能獲得第一個有意義的(頁面)繪製,或者(說)讓 App 可互動。 Lighthouse 高亮標識了我們網站的一堆問題,而 23 分的整體效能得分充分反映了這一點。
頁面大小約3.4MB - 我們迫切需要減減肥了。
我們的首次效能挑戰由此開始:找到可以輕鬆刪除的內容,同時不影響整體體驗。
效能優化機會
有一些顯而易見的東西可以安全刪除掉:空白和評論。
圖4. Minify和壓縮 JavaScript 和 CSS
Lighthouse 在 Unminified CSS & JavaScript 審查中突出了這個機會。程式使用 webpack 進行構建,因此為了縮小體積,我們選擇了 Uglify JS 外掛。
縮小體積是一項常見任務,因此你得找到適合你的構建過程的現成解決方案。
該專案中另一個有用的審查是啟用文字壓縮。我們沒有理由傳送未壓縮的檔案,而且現在大多數 CDN 都開箱即用地支援這個。
我們使用 Firebase Hosting 來託管我們的程式碼,Firebase 預設啟用 gzip,因此,通過在合理的 CDN 上託管我們的程式碼,我們免費獲得了這個功能。
雖然 gzip 是一種非常流行的壓縮方式,但其他機制如 Zopfli 和 Brotli 也越來越吸引人。 Brotli 受大多數瀏覽器支援,你可以在將資源傳送到伺服器之前使用二進位制方式對其進行預壓縮。
我們的下一步是確保在不必要的情況下我們不會重複傳送資源。
Lighthouse 中的低效快取策略審查使我們注意到,我們可以通過優化快取策略實現這一目標。通過在我們的伺服器中設定 max-age 過期頭,我們可以確保在重複訪問情況下,使用者可以重用他們之前下載的資源。
理想情況下,你應該在儘可能長的時間內儘可能安全地快取儘可能多的資源,並提供驗證令牌,以便高效地重新驗證已更新的資源。
到目前為止,我們刪除了非必要下載檔案的顯要部分,那不太明顯的部分呢?例如,未使用的程式碼。
圖5.檢查程式碼覆蓋率
有時我們會在 App 中包含不必要的程式碼。這種情況尤其是在你的 App 開發了很長一段時間,你的團隊或你的依賴項發生了變化,有時“孤兒庫”被遺忘的情況下。這正是我們經歷過的事情。
最初我們使用 Material Components 庫來快速構建我們的 App 原型。隨著時間的推移,我們轉向了更加定製化的外觀,我們完全忘記了這個庫。幸運的是,程式碼覆蓋率檢查幫助我們在 bundle 中重新發現了它。
你可以在 DevTools 中檢查程式碼覆蓋率狀態,包括執行時和應用載入時間。你可以在底部截圖中看到兩個大的紅色橫條 - 我們有超過 95% 的 CSS 是未使用的,還有一大堆 JavaScript。
Lighthouse 在未使用的 CSS 規則審查中也提到了這個問題。它表示我們可能節省超過 400kb。所以我們回到程式碼裡,刪除了該庫的 JavaScript 和 CSS 部分。
圖6. 棄用 MVC 介面卡,我們的樣式下降到了 10KB!
這使我們的 CSS bundle 減少了 20倍,這對於一個很小的,兩行長的 commit 來說太讚了。
當然,它使我們的效能得分上升,而且可互動時間也得到優化。
但是,通過這樣的更改,僅僅檢查指標和分數是不夠的。刪除實際程式碼絕不是零風險的,因此你應該始終注意發掘潛在的風險。
我們的程式碼在 95% 的程式碼中未被使用 - 在某處仍有 5% 在使用。顯然我們的某個元件仍在使用該庫中的樣式 - 塗鴉滑塊中的小箭頭。因為它太小了,我們可以手動將這些樣式合併到按鈕中。
圖7.一個元件仍在使用已刪除的庫
因此,如果您刪除程式碼,請確保您擁有適當的測試工作流,以幫助您防範潛在的可見的風險迴歸。
我們知道大量資源可能會減慢網頁載入速度。他們可能會消耗使用者的錢,他們可能會對他們的資料計劃產生重大影響,因此注意這一點非常重要。
通過使用巨大的網路負載審查,Lighthouse 能夠檢測到我們的某些網路負載存在的問題。
圖8.檢測巨大的網路負載
從這裡可以看到,我們有超過 3mb 的程式碼被傳輸 - 這不是一般的多,特別是在移動裝置上。
在這個列表的最頂部,Lighthouse 告訴我們有一個2mb大小的未壓縮JavaScript vendor 包。這也是 webpack 高亮顯示的問題。
俗話說:最快的請求是還沒發出的請求。
理想情況下,你應該衡量你傳送給使用者的每一項資源的價值,衡量這些資源的效能,並根據初始經驗判斷它是否真的值得被傳輸。因為有時這些資源可以在空閒時間延遲傳送,懶載入或處理。
在我們的例子中,因為我們處理的是大量的 JavaScript 包,所以我們很幸運,因為 JavaScript 社群擁有豐富的 JavaScript 包審查工具。
圖9. JavaScript 包審查
我們開始使用 webpack bundle analyzer,它告訴我們,我們有一個名為 unicode 的依賴項,它是 1.6mb 的已解析 JavaScript,非常大的檔案。
然後我們轉到我們的編輯器,並使用為視覺化程式碼準備的 Import Cost 外掛,透過它我們能夠看到我們匯入的每個模組的成本。它能幫助我們發現哪個元件包含引用此模組的程式碼。
然後我們切換到另一個工具 BundlePhobia。這個工具允許你輸入任何 NPM 包的名稱,並實際看到它經過壓縮和 gzip 後的預計大小。我們找到了一個很好的替代方案,我們使用的 slug 模組只有 2.2kb,所以我們用了它。
這對我們的效能產生了很大的影響。在此更改和發現其他減少 JavaScript 包大小的機會之間,我們節省了 2.1mb 的程式碼。
綜合考慮到這些 bundle 的壓縮和縮小尺寸,我們總體上看到了 65% 的提升。我們發現這確實值得去做。
因此,總的來說,嘗試去消除你的網站和應用中不必要的下載吧。對資源進行清點並衡量其效能影響,這可能會帶來煥然一新的改變,因此請確保定期審查你的資源。
通過程式碼拆分降低 JavaScript 啟動時間
雖然大型網路負載可能對我們的應用程式產生重大影響,但還有另一樣東西也能產生巨大影響——那就是 JavaScript。
JavaScript 是你最昂貴的資產。在移動裝置上,如果您傳送了大量的 JavaScript,它可能會延遲使用者與介面元件互動的時間。這意味著他們點選 UI 的操作可能是毫無意義的。因此,瞭解 JavaScript 成本為何如此之高顯得極為重要。
這是瀏覽器處理 JavaScript 的方式。
圖10. JavaScript 處理
我們首先必須下載該指令碼,我們的 JavaScript 引擎需要解析該程式碼,編譯並執行它。
現在,這些(處理)階段在臺式機或筆記本等高階裝置、甚至是高階手機並不用花很長時間。但在中等配置手機上,這個過程可能要花上 5 到 10 倍的時間。這正是延遲互動的原因,因此把它降下來非常關鍵。
為了幫你發現 App 的這些問題,我們向 Lighthouse 引入了一個新的 JavaScript 啟動時間審查工具。
圖11. JavaScript 啟動時間審查
在 Oodle App 的例子中,它顯示我們花了 1.8 秒來啟動 JavaScript。而這段時間所做的,是將所有路由和元件靜態匯入到一整個 JavaScript 包中。
解決此問題的方法之一是使用程式碼分割。
程式碼分割的概念是,不要一次把一整個披薩的 JavaScript 給到你的使用者,不妨一次給只他們所需要的一片?
程式碼分割可以應用於路由級別或元件級別。它適用於 React 和 React Loadable,Vue.js,Angular,Polymer,Preact 以及其他多個庫。
我們將程式碼分割合併到我們的應用中,從靜態匯入切換為動態匯入,實現了我們所需的非同步懶載入程式碼。
圖13.使用動態匯入的程式碼分割
這種影響既縮小了 bundle 的大小,也節省了我們的 JavaScript 啟動時間。它把時間降到了 0.78 秒,為應用提速 56%。
通常,如果你正在構建你的 JavaScript 體驗,請務必做到僅向用戶傳送他們所需要的程式碼。
利用程式碼分割等概念,發掘 tree shaking 等思路,檢視 webpack-libs-optimizations 倉庫,瞭解在使用 webpack 時如何減小庫的體積的方法。
優化圖片
圖片載入效能的笑話
在 Oodle App 中,我們使用了大量圖片。不幸的是,Lighthouse 對它的熱情遠遠低於我們。事實上,我們在所有三個與圖片相關的審查上都掛掉了。
我們忘了對圖片進行優化,沒有正確處理好它們的體積,我們也本可以使用其他圖片格式來優化。
圖14. Lighthouse 影象審查
我們開始對圖片進行優化。
針對一次性的優化,你可以使用 ImageOptim 或 XNConvert 等視覺化工具。
更自動化的方法是使用像 imagemin 這樣的庫,在構建過程中優化圖片。
這樣,你就可以確保將來新增的圖片自動得到優化。一些 CDN,例如 Akamai 或 Cloudinary 或 Fastly 等第三方解決方案,也提供了全面的影象優化解決方案。所以你也可以放心地把圖片託管到這些服務上。
如果由於成本或延遲問題而不想這麼幹,Thumbor 或 Imageflow 等專案也提供自託管替代方案。
圖15.優化前後
我們的背景 PNG 圖片在 webpack 中被標記為大,事實的確如此。在將調整到 viewport 大小,並通過 ImageOptim 優化後,我們把體積降到了 100kb,還可以接受。
我們對網站上的圖片重複執行了此操作,由此顯著降低了整體頁面的體積。
為動畫內容使用正確的格式
GIF 的代價極其昂貴。令人驚訝的是,GIF 格式從未打算成為動畫平臺。因此,切換到更合適的視訊格式可以大大節省檔案大小。
在 Oodle App 中,我們在主頁上使用了 GIF 作為介紹動畫。根據 Lighthouse 的說法,切換到更高效的視訊格式能節省超過 7mb。我們的動畫就差不多 7.3mb 了,這對於任何網站來說都太大了,所以我們把它變成了一個包含兩個原始檔的視訊元素——mp4 和 WebM,以相容更多瀏覽器。
圖16.用視訊替換動畫 GIF
我們使用 FFmpeg 工具將動畫 GIF 轉換為 mp4 檔案。 WebM 格式則節省得更多——ImageOptim API 可以做這種轉換。
這種轉換為我們節省了超過 80% 的總體積。這讓我們降到了 1mb 左右。
儘管如此,1mb 仍算是網路傳輸中的大型資源,特別是對於頻寬受限的使用者而言。幸好,我們可以使用 Effective Type API 來檢測到它們處於慢網路,然後給它們提供體積更小的 JPEG。
此介面使用高效的往返時間和降低值來判斷使用者所用的網路型別。它只返回一個字串,像 slow 2G,2G,3G 或 4G。因此,根據此值,對 4G 以下的使用者,我們使用影象替換掉了視訊元素。
它確實犧牲了一點點使用者體驗中,但至少在慢網路中,該站點也是可用的了。
懶載入螢幕外圖片
輪播動畫,滑塊或非常長的頁面通常會載入影象,即使使用者並不能立即在頁面上看到它們。
Lighthouse 將在螢幕外影象稽核中標記此行為,您也可以在 DevTools 的網路面板中自行檢視。如果你看到很多影象傳入,但它們之中只有少數可見,則意味著你可以考慮延遲載入它們。
瀏覽器本身尚不支援懶載入,因此我們必須使用 JavaScript 來新增此功能。我們使用 Lazysizes 庫為我們的 Oodle 封面新增懶載入行為。
Lazysizes 非常智慧,因為它不僅可以跟蹤元素的可見性變化,還可以主動預獲取檢視附近的元素,以獲得最佳的使用者體驗。它還提供了 IntersectionObserver 的可選整合,為你帶來非常高效的可見性查詢。
在此更改後,我們的圖片將按需提取。如果你想深入瞭解該主題,請檢視 images.guide - 一個非常方便和全面的資源。
images.guide: https://images.guide/
幫助瀏覽器儘早提供關鍵資源
並非每個通過網路傳送到瀏覽器的位元組都具有同等的重要性,瀏覽器知道這一點。許多瀏覽器都有試探性方法來決定他們應該首先獲取什麼。所以有時它們會在獲取圖片或指令碼之前獲取 CSS。
可能有用的東西是作為頁面作者的我們,可以告訴瀏覽器對我們來說真正重要的是什麼。值得慶幸的是,在過去幾年中,瀏覽器已經添加了許多功能來幫助我們實現這一功能,例如:使用 link rel=preconnect,preload 或 prefetch 實現資源提示。
這些 Web 平臺的功能可以幫助瀏覽器在正確的時間獲取正確的資源,並且它們會比使用指令碼完成的一些自定義載入,基於邏輯的方法更有效。
讓我們看看 Lighthouse 如何實際指導我們有效地使用這些功能。
Lighthouse 讓我們做的第一件事就是避免多次與任一源的昂貴往返請求。
圖17.避免多次與任一源的昂貴往返請求
對於 Oodle App,我們實際上重度使用 Google 字型。每當在頁面中使用 Google Fonts 樣式表時,它最多會連線兩個子域。Lighthouse 告訴我們,如果我們能夠預熱這種連線,我們可以在初次連線時節省最多 300 毫秒。
利用 link rel preconnect,我們可以有效地遮蔽連線延遲。
特別是對像 Google Fonts 這種把字型 CSS 託管在 googleapis.com 上,以及把字型資源託管在 Gstatic 上的資源,這可能會產生很大的影響。所以我們應用了這個優化,優化了幾百毫秒。
Lighthouse 建議的下一件事是預先載入關鍵請求。
圖18.預載入關鍵請求
<link rel=preload> 非常強大,它通知瀏覽器當前導航中需要該資源,並且嘗試讓瀏覽器儘快獲取它。
現在,Lighthouse 告訴我們,我們應該預載入我們的關鍵網路字型資源,因為我們正在載入兩種網路字型。
預載入網路字型如下所示 - 指定rel = preload,將字型型別傳入 as 欄位,然後指定要載入的字型型別,例如 woff2。
這對你的頁面產生的影響將非常明顯。
圖19.預載入資源的影響
通常,如果不使用 link rel preload,如果 Web 字型恰好對你的頁面至關重要,那麼瀏覽器必須做的是首先獲取 HTML,解析 CSS,以及接下來的其他資源,最後才去獲取你的網路字型。
而使用了 link rel preload,一旦瀏覽器解析了 HTML,它就可以提早開始獲取這些網路字型。對我們的 App 來說,這可以減少我們使用 Web 字型渲染文字所花費的時間。
現在,如果你想嘗試使用 Google Fonts 預載入字型,那還沒那麼簡單,我們還有一個問題。
我們在樣式表中的字型中指定的 Google Font URL 恰好是 Google 字型團隊定期更新的內容。這些 URL 可能會過期或定期更新,因此,如果你希望完全控制字型載入體驗,我們建議你自行託管你的 Web 字型。這也很棒,因為它讓你可以訪問 link rel preload 等內容。
在我們的例子中,我們發現 Google Web Fonts Helper 工具在幫助我們離線某些網路字型並在本地設定它們時非常有用,因此請了解下該工具。
無論你是將 Web 字型還是 JavaScript 作為關鍵資源的一部分,都應使瀏覽器儘快提供該關鍵資源。
實驗:優先順序提示
今天還有一個特別的東西要與你分享。除了資源提示和預載入等功能外,我們還在開發一種全新的實驗性瀏覽器功能,我們稱之為優先順序提示。
圖20.優先順序提示
這項新功能允許你提示瀏覽器某資源的重要性。它暴露了一個新屬性 - importance - 可取值 low,high 或 auto。
這使我們能降低不太重要資源的優先順序,例如非關鍵樣式,圖片或 fetch API 呼叫,以減少流量搶佔。我們還可以提升更重要事物的優先順序,例如我們的英雄圖片。
對於我們的 Oodle App,這實際上給了我們一個可以優化的機會。
圖21.設定初識可見內容的優先順序
在我們對影象設定懶載入之前,瀏覽器的做法是,我們將這個圖片輪播與所有塗鴉一起使用,而瀏覽器會在輪播最開始時以高優先順序獲取所有影象。不幸的是,輪播中間的影象對使用者來說是最重要的。所以我們的做法是,將背景影象的重要性設定得非常低,前景影象的重要性設定得非常高,這在慢速 3G 時能帶來 2 秒的提速,我們也能夠快速地獲取和渲染這些影象。這是一個很棒的體驗。
我們希望在幾周內將這個功能帶到 Canary,還請密切關注。
制定一個網路字型載入策略
排版是良好設計的基礎,如果你使用的是網路字型,理想情況下你並不想阻塞文字的渲染,而且你絕對不想顯示不可見的文字。
我們在 Lighthouse 中強調了這一點,在 avoid invisible text while web fonts are loading 審查中可以找到。
圖22.在載入網路字型時避免使用不可見文字
如果你使用 font face 程式碼塊載入網路字型,並且該字型需要較長時間才能獲取到,你就是在讓瀏覽器決定該做什麼。有些瀏覽器會在退回到系統字型之前等待最多三秒鐘,並且一旦字型下載完畢,瀏覽器最終又會切換到字型。
我們試圖避免這種不可見文字,在這種情況下,如果網路字型載入花了太長時間,我們將無法看到本週的經典塗鴉。幸好,通過一個名為 font-display 的新功能,你實際上可以更好地控制這個過程。
Font display 可幫助你根據交換所需的時間來決定網路字型的渲染或退階方式。
在這種情況下,我們使用字型顯示交換。交換為字型提供零秒塊週期和無限交換週期。這意味著如果字型載入需要一段時間,瀏覽器會立即使用備用字型繪製文字。一旦字型可用,它就會轉換它。
對我們的 App 來說,這功能非常棒,它允許我們很早就顯示一些有意義的文字,並在網路字型準備好後馬上轉換過去。
圖23.字型顯示結果
一般情況下,如果你碰巧在使用網路字型,且它佔據了網路的很大一部分,那麼你得有一個很好的網路字型載入策略。
有許多 Web 平臺能幫你優化字型的載入體驗,你還可以檢視 Zach Leatherman 的 Web Font Recipes 倉庫,因為它實在太棒了。
Web Font Recipes repo: https://www.zachleat.com/web/recipes/
減少渲染阻塞指令碼
我們的應用中還有其他部分可以在下載鏈中提前推送,以便提前提供一些基本的使用者體驗。
在 Lighthouse 時間軸上,你可以看到在載入所有資源的前幾秒內,使用者無法看到任何內容。
圖24.減少阻塞式渲染樣式表的機會
下載和處理外部樣式表阻塞了我們的渲染過程的進展。
我們可以嘗試通過先提供一些樣式來優化我們的關鍵渲染路徑。
如果我們提取負責初始渲染的樣式並在 HTML 中內聯它們,瀏覽器可以直接渲染它們而無需等待外部樣式表。
在我們的例子中,我們使用名為 Critical 的 NPM 模組在構建步驟中內聯 index.html 中的關鍵內容。
雖然這個模組為我們完成了大部分繁重工作,但要讓它在不同路線上順利執行仍然有點棘手。
如果你不小心或者你的站點結構非常複雜,若你沒有從一開始就規劃 app shell 架構,那麼引入這種模式可能非常困難。
這就是為什麼在早期就考慮效能因素非常重要的原因。如果你從一開始就沒有設計效能,那麼之後再實施就可能遇到問題。
最終我們的風險得到了回報,我們設法讓它發揮作用,App開始更早地提供內容,顯著改善了我們的第一個有意義的繪畫時間。
結果
這是我們應用在網站上的一長串效能優化。我們來看看結果。結果表明了我們的應用在優化之前和之後,在中等裝置、3G 網路上是如何載入的。Lighthouse 表現得分從 23 上升到 91。在速度方面取得了相當不錯的進步。所有這些變化都是由我們不斷檢查並遵循 Lighthouse 報告推動的。如果你想了解我們如何在技術上實施所有改進,請隨時檢視我們的倉庫(http://github.com/google/oodle-demo),尤其是 PR。
預測效能 - 資料驅動的使用者體驗
我們相信機器學習在未來的許多領域代表著令人興奮的機會。我們希望將來能引發更多實驗的一個想法是,真實資料可以真正指導我們正在建立的使用者體驗。
今天,我們對使用者可能想要或需要的內容做出了很多武斷的決定,由此判斷什麼資源該預先提取,預載入或預先快取。如果我們猜對了,我們可以優先考慮少量資源,但很難將其擴充套件到整個網站。
我們實際上有資料可以更好地為我們的優化提供支援。使用 Google Analytics reporting API,我們可以檢視下一個首頁以及我們網站上任意網址的退出百分比,從而得出我們應優先考慮哪些資源的結論。
如果我們將其與良好的概率模型相結合,我們就會通過積極預獲取內容來避免浪費使用者的資料。我們可以利用 Google Analytics 資料,並使用機器學習和馬爾可夫鏈或神經網路等模型來實現此類模型。
圖25.用於Web應用程式的資料驅動捆綁
為了促進這個實驗,我們很高興地宣佈一個叫做 Guess.js 的新計劃。
圖26. Guess.js
Guess.js 是一個專注於資料驅動Web使用者體驗的專案。我們希望它能激發人們探索使用資料來改善網路效能並超越它。它是完全開源的,可以 GitHub 上獲取。這是由 Minko Gechev,Gatsby 的 Kyle Matthews,Katie Hempenius 和其他一些人與開源社群合作建立的。
總結
分數和指標有助於提高 Web 的速度,但它們只是手段,而不是目標本身。
我們都經歷過慢網速頁面載入,但我們現在有機會為使用者提供更加愉悅的快速載入體驗。
效能提升是一個旅程。許多小的變化可以帶來巨大的收益。通過使用正確的優化工具並密切關注 Lighthouse 報告,你可以為使用者提供更好、更具包容性的體驗。
特別感謝:Ward Peeters,Minko Gechev,Kyle Mathews,Katie Hempenius,Dom Farolino,Yoav Weiss,Susie Lu,Yusuke Utsunomiya,Tom Ankers,Lighthouse 和 Google Doodles。
英文原文:
https://developers.google.com/web/updates/2018/08/web-performance-made-easy
“UC國際技術”致力於與你共享高質量的技術文章
歡迎關注我們的公眾號、將文章分享給你的好友