<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          適合所有網(wǎng)站的前端優(yōu)化技巧,值得你收藏!

          共 10515字,需瀏覽 22分鐘

           ·

          2021-04-24 05:58

          導(dǎo)讀:本文雖然明指了某個(gè)主頁(yè),但是其實(shí)是適合所有網(wǎng)站系統(tǒng)前端的優(yōu)化技巧的。

          最近,我們將 Universe.com 主頁(yè)的性能提升了十倍以上。在本文中,我們將解析實(shí)現(xiàn)這一重大改進(jìn)的具體技術(shù)手段。

          但在開(kāi)始之前,讓我們先對(duì)網(wǎng)絡(luò)性能的重要意義進(jìn)行一番論證(博文末尾提供相關(guān)案例研究鏈接):

          • 用戶體驗(yàn): 糟糕的性能可能導(dǎo)致響應(yīng)失敗,從 UI 與 UX 的角度來(lái)看,這可能會(huì)引發(fā)用戶的沮喪情緒。

          • 客戶轉(zhuǎn)化與收入: 網(wǎng)站速度緩慢通常會(huì)導(dǎo)致客戶流失,并對(duì)轉(zhuǎn)化率與收入產(chǎn)生負(fù)面影響。

          • SEO: 從 2019 年 7 月 1 日開(kāi)始,谷歌公司開(kāi)始在全部新網(wǎng)站上默認(rèn)啟用移動(dòng)優(yōu)先索引。如果網(wǎng)站在移動(dòng)設(shè)備上運(yùn)行緩慢,且沒(méi)有針對(duì)移動(dòng)設(shè)備進(jìn)行內(nèi)容格式調(diào)整,那么網(wǎng)站的搜索排名將會(huì)降低。

          在本篇文章中,我們將簡(jiǎn)要介紹以下幾大有助于我們提高頁(yè)面性能的主要領(lǐng)域:

          • 性能測(cè)量: 實(shí)驗(yàn)室與現(xiàn)場(chǎng)工具測(cè)量。

          • 渲染: 客戶端與服務(wù)器端渲染、預(yù)渲染以及混合渲染方法。

          • 網(wǎng)絡(luò): CDN、緩存、GraphQL 緩存、編碼、HTTP/2 以及 Server Push。

          • 瀏覽器中的 JavaScript: 數(shù)據(jù)包大小預(yù)算、代碼拆分、async 與 defer 腳本、圖像優(yōu)化(WebP、延遲加載、漸進(jìn)式設(shè)計(jì))以及資源提示(preload、prefetch 與 preconnect)。

          這里再介紹一點(diǎn)我們的情況:我們的主頁(yè)由 React(TypeScript)、Phoenix(Elixir)、Puppeteer(headless Chrome)以及 GraphQL API(Ruby on Rails)構(gòu)建而成。以下為主頁(yè)在移動(dòng)設(shè)備上顯示的效果:

          Universe 主頁(yè)與瀏覽效果

          性能測(cè)量

          沒(méi)有數(shù)據(jù)作為支持,一切意見(jiàn)都將毫無(wú)意義。

          —— W. Edwards Deming

          實(shí)驗(yàn)室工具

          實(shí)驗(yàn)室工具能夠立足受控環(huán)境從預(yù)定義的設(shè)備及網(wǎng)絡(luò)設(shè)置中收集數(shù)據(jù)。利用這些工具,我們能夠輕松調(diào)試任何性能問(wèn)題并實(shí)現(xiàn)良好的可重復(fù)測(cè)試。

          Lighthouse 就是一款立足本地計(jì)算機(jī)對(duì) Chrome 內(nèi)網(wǎng)頁(yè)進(jìn)行審計(jì)的出色工具。其能夠提供一系列關(guān)于如何提高性能、可訪問(wèn)性以及搜索引擎優(yōu)化的實(shí)用性提示。下面,我們來(lái)看模擬高速 3G 加 4x CPU 場(chǎng)景下的 Lighthouse 性能審計(jì)報(bào)告:

          之前與之后:首屏內(nèi)容填充(簡(jiǎn)稱(chēng) FCP)性能實(shí)現(xiàn) 10 倍提升

          然而,單純使用實(shí)驗(yàn)室工具也會(huì)帶來(lái)不少弊端:這類(lèi)工具不一定能準(zhǔn)確反映出最終用戶所面臨的設(shè)備、網(wǎng)絡(luò)、位置以及多種其它現(xiàn)實(shí)因素造成的性能瓶頸。正因?yàn)槿绱耍覀儾判枰浜犀F(xiàn)場(chǎng)工具進(jìn)行補(bǔ)充。

          現(xiàn)場(chǎng)工具

          現(xiàn)場(chǎng)工具允許我們模擬并測(cè)量用戶的真實(shí)頁(yè)面負(fù)載。目前有多種服務(wù)可幫助大家從實(shí)際設(shè)備當(dāng)中獲取真實(shí)性能數(shù)據(jù):

          • WebPageTest?—?允許用戶立足不同位置上的實(shí)際設(shè)備對(duì)不同瀏覽器進(jìn)行性能測(cè)試。

          • Test My Site?—?使用 Chrome 用戶體驗(yàn)報(bào)告 (CrUX) 功能,并以 Chrome 使用情況統(tǒng)計(jì)為基礎(chǔ);這款工具公開(kāi)可用且每月更新一次。

          • PageSpeed Insights?—?將實(shí)驗(yàn)室(Lighthouse)與現(xiàn)場(chǎng)(CrUX)數(shù)據(jù)加以結(jié)合。

          WebPageTest 報(bào)告

          渲染

          內(nèi)容的渲染可通過(guò)多種方法實(shí)現(xiàn),其中每一種都擁有獨(dú)特的優(yōu)勢(shì)與缺點(diǎn):

          • 服務(wù)器端渲染 (SSR) 是指在服務(wù)器端為瀏覽器提供最終 HTML 文檔的過(guò)程。優(yōu)勢(shì):搜索引擎可以直接抓取網(wǎng)站而無(wú)需執(zhí)行 JavaScript(SEO)、快速初始頁(yè)面加載、代碼僅存在于服務(wù)器端。短板:非富網(wǎng)站交互、整頁(yè)重新加載、瀏覽器功能受限。

          • 客戶端渲染是指利用 JavaScript 在瀏覽器當(dāng)中進(jìn)行內(nèi)容渲染的過(guò)程。優(yōu)勢(shì):富網(wǎng)站交互、在初始加載后可快速呈現(xiàn)路由變更內(nèi)容、支持現(xiàn)代瀏覽器功能(例如配合 Service Workers 實(shí)現(xiàn)離線支持)。短板:SEO 友好性差、初始頁(yè)面加載緩慢、通常需要在服務(wù)器端實(shí)現(xiàn)單頁(yè)面應(yīng)用程序(SPA)與 API。

          • 預(yù)渲染類(lèi)似于服務(wù)器端渲染方法,但渲染會(huì)提前發(fā)生在構(gòu)建時(shí)而非運(yùn)行時(shí)。優(yōu)勢(shì):built 靜態(tài)支持文件通常比服務(wù)器運(yùn)行方法更簡(jiǎn)單、SEO 友好性高、快速初始頁(yè)面加載。短板:需要在執(zhí)行任何代碼變更時(shí)提前進(jìn)行完整頁(yè)面重新加載、非富網(wǎng)站交互、瀏覽器功能訪問(wèn)限制。

          客戶端渲染

          以前,我們將自己的主頁(yè)與 Ember.js 框架一同實(shí)現(xiàn)為采用客戶端渲染方法的單頁(yè)面應(yīng)用。但這種法的一大問(wèn)題在于,我們的 Ember.js 應(yīng)用程序包過(guò)大。這意味著在瀏覽器下載 JavaScript 文件并對(duì)其進(jìn)行解析、編譯與執(zhí)行的過(guò)程中,用戶只能對(duì)著空白屏幕發(fā)呆:

          最要命的空白屏幕

          因此,我們決定利用 React 重構(gòu)應(yīng)用當(dāng)中的某些部分。

          • 我們的開(kāi)發(fā)人員已經(jīng)非常熟悉 React 應(yīng)用程序的構(gòu)建方法(例如嵌入式功能部件)。

          • 我們已經(jīng)擁有多個(gè) React 組件庫(kù)可在多個(gè)項(xiàng)目間隨意共享。

          • 新的頁(yè)面中將可包含一些交互式 UI 元素。

          • 龐大的 React 生態(tài)系統(tǒng)能夠提供多種工具方案。

          • 利用瀏覽器中的 JavaScript,我們可以通過(guò)多項(xiàng)強(qiáng)大功能構(gòu)建起漸進(jìn)式 Web 應(yīng)用。

          預(yù)渲染與服務(wù)器端渲染

          客戶端渲染應(yīng)用程序的具體構(gòu)建——例如采用 React Router DOM,仍然會(huì)帶來(lái)與 Ember.js 相同的問(wèn)題。JavaScript 需要占用大量資源,而且訪問(wèn)者需要經(jīng)歷一段首屏內(nèi)容填充周期才能看到實(shí)際內(nèi)容。

          因此在決定使用 React 之后,我們開(kāi)始嘗試其它潛在的渲染選項(xiàng),以確保瀏覽器能夠更快地完成內(nèi)容渲染。

          使用 React 時(shí)的常規(guī)渲染選項(xiàng)

          • Gatsby.js 允許我們利用 React 與 GraphQL 構(gòu)建預(yù)渲染頁(yè)面。Gatsby.js 是一款強(qiáng)大的工具,能夠直接提供多種性能優(yōu)化方案。然而,預(yù)渲染方法并不適合我們的需求,因?yàn)槲覀兊木W(wǎng)站中可能存在無(wú)數(shù)包含用戶生成內(nèi)容的頁(yè)面。

          • Next.js 是一套高人氣 Node.js 框架,允許用戶通過(guò) React 實(shí)現(xiàn)服務(wù)器端渲染。然而,Next.js 設(shè)定了太多條條框框,要求用戶使用它提供的路由機(jī)制以及 CSS 解決方案等等。另外,我們的現(xiàn)有組件庫(kù)是專(zhuān)為瀏覽器構(gòu)建的,與 Node.js 并不兼容。

          因此,我們打算嘗試一下混合方法,即發(fā)揮每一種渲染選項(xiàng)中的獨(dú)特優(yōu)勢(shì)。

          運(yùn)行時(shí)預(yù)渲染

          Puppeteer 是一套 Node.js 庫(kù),允許用戶使用 headless Chrome。我們希望嘗試?yán)?Puppeteer 在運(yùn)行時(shí)當(dāng)中實(shí)現(xiàn)預(yù)渲染。這代表著一種有趣的混合方法:利用 Puppeteer 進(jìn)行服務(wù)器端渲染,同時(shí)利用 hydration 進(jìn)行客戶端渲染。感興趣的朋友可以點(diǎn)擊此處查看谷歌提供的關(guān)于如何利用 headless 瀏覽器進(jìn)行服務(wù)器端渲染的相關(guān)提示。

          利用 Puppeteer 對(duì) React 應(yīng)用程序進(jìn)行運(yùn)行時(shí)預(yù)渲染

          這種方法具備以下優(yōu)勢(shì):

          • 允許 SSR,因此有利于 SEO 優(yōu)化。抓取程序不需要執(zhí)行 JavaScript 即可看到網(wǎng)頁(yè)內(nèi)容。

          • 允許一次性構(gòu)建起簡(jiǎn)單的瀏覽器 React 應(yīng)用程序,而后將其同時(shí)用于服務(wù)器端與瀏覽器內(nèi)。這將同時(shí)提高瀏覽器應(yīng)用與 SSR 的速度表現(xiàn),一舉兩得。

          • 利用 Puppeteer 在服務(wù)器端渲染頁(yè)面,在速度上一般快于在最終用戶的移動(dòng)設(shè)備上進(jìn)行渲染(前者網(wǎng)絡(luò)連接更強(qiáng)、硬件配置也更高)。

          • Hydration 允許我們構(gòu)建起富 SPA,并可訪問(wèn) JavaScript 的瀏覽器功能。

          • 我們不再需要預(yù)先了解所有可能被調(diào)用的頁(yè)面,也不需要預(yù)先進(jìn)行渲染。

          但在采用這種方法的過(guò)程中,我們也遇到了一些挑戰(zhàn):

          • 吞吐量是最主要的問(wèn)題。每項(xiàng)請(qǐng)求都會(huì)在單獨(dú)的 headless 瀏覽器進(jìn)程當(dāng)中占用大量資源。雖然我們可以使用單一 headless 瀏覽器進(jìn)程并在其中的各個(gè)選項(xiàng)卡內(nèi)運(yùn)行多項(xiàng)請(qǐng)求,但使用多個(gè)選項(xiàng)卡仍會(huì)降低整個(gè)進(jìn)程的性能水平。

          利用 Puppeteer 的服務(wù)器端渲染架構(gòu)

          ?    穩(wěn)定性。對(duì)眾多 headless 瀏覽器進(jìn)行規(guī)模伸縮,同時(shí)保持進(jìn)程不致過(guò)熱并實(shí)現(xiàn)負(fù)載均衡絕對(duì)是一項(xiàng)高難挑戰(zhàn)。我們嘗試了不同的托管方法,包括在 Kubernetes 集群內(nèi)進(jìn)行自托管,以及利用 AWS Lambda 與 Google Cloud Functions 實(shí)現(xiàn)無(wú)服務(wù)器計(jì)算。我們注意到,后一種方法在配合 Puppeteer 時(shí)存在一些性能問(wèn)題:

          AWS Lambdas和GCP函數(shù)的Puppeteer響應(yīng)時(shí)間

          在配合 AWS Lambdas 與 GCP Functions 時(shí),Puppeteer 的響應(yīng)時(shí)間結(jié)果隨著我們對(duì) Puppeteer 熟悉程度的逐步提升,我們開(kāi)始對(duì)初始方法進(jìn)行迭代(后文將具體說(shuō)明)。我們還進(jìn)行了其它一系列有趣的實(shí)驗(yàn),希望通過(guò) headless 瀏覽器渲染 PDF。再有,即使不編寫(xiě)任何代碼,我們也能夠利用 Puppeteer 自動(dòng)進(jìn)行端到端測(cè)試。而且除了 Chrome 之外,Puppeteer 現(xiàn)在還支持 Firefox 瀏覽器。

          混合渲染方法

          在運(yùn)行時(shí)中使用 Puppeteer 并非易事。正因?yàn)槿绱耍覀儾艣Q定在構(gòu)建時(shí)中加以使用,同時(shí)配合一款工具用于在運(yùn)行時(shí)內(nèi)從服務(wù)器端獲取用戶生成的實(shí)際內(nèi)容。很明顯,這款工具必須擁有比 Puppeteer 更強(qiáng)大的穩(wěn)定性與吞吐能力。

          我們決定使用 Elixir 編程語(yǔ)言。Elixir 看起來(lái)與 Ruby 非常相似,但運(yùn)行在 BEAM(Erlang VM)之上。順帶一提,BEAM 專(zhuān)門(mén)為構(gòu)建高容錯(cuò)、高穩(wěn)定性系統(tǒng)而生。

          Elixir 采用 Actor 并發(fā)模型。每個(gè)“Actor”(即 Elixir 進(jìn)程)的內(nèi)存占用量都非常有限,僅為 1 到 2 KB。這意味著系統(tǒng)將能夠同時(shí)運(yùn)行成千上萬(wàn)個(gè)獨(dú)立的進(jìn)程。Phoenix 則是一套 Elixir Web 框架,能夠支持高吞吐量,并允許開(kāi)發(fā)者在各個(gè)獨(dú)立的 Exlixir 進(jìn)程當(dāng)中處理各項(xiàng) HTTP 請(qǐng)求。

          我們將上述方法結(jié)合起來(lái),充分利用其各自?xún)?yōu)勢(shì),希望能夠切實(shí)滿足自身需求:

          Puppeteer 用于實(shí)現(xiàn)預(yù)渲染,Phoenix 則用于實(shí)現(xiàn)服務(wù)器端渲染

          • Puppeteer 在構(gòu)建時(shí)中按照我們預(yù)期的方式對(duì) React 頁(yè)面進(jìn)行預(yù)渲染,并將結(jié)果保存為 HTML 文件(來(lái)自 PRPL 模式的 app shell)。

          我們可以繼續(xù)構(gòu)建一款簡(jiǎn)單的瀏覽器 React 應(yīng)用程序,并在無(wú)需等待最終用戶設(shè)備 JavaScript 處理過(guò)程的同時(shí)獲得快速初始頁(yè)面加載效果。

          • 我們的 Phoenix 應(yīng)用負(fù)責(zé)實(shí)現(xiàn)頁(yè)面預(yù)渲染,并以動(dòng)態(tài)方式將實(shí)際內(nèi)容注入至 HTML。這就使得內(nèi)容的 SEO 友好性大幅提升,讓按需處理大量多種頁(yè)面成為可能,并顯著降低了擴(kuò)展難度。

          • 客戶端接收并立即開(kāi)始顯示 HTML,而后由 Hydration 將 React DOM 狀態(tài)持續(xù)作為常規(guī) SPA。如此一來(lái),我們就構(gòu)建起了高度交互的應(yīng)用程序,并可訪問(wèn)各項(xiàng) JavaScript 瀏覽器功能。

          利用 Puppeteer 建立預(yù)渲染架構(gòu),利用 Phoenix 進(jìn)行服務(wù)器端渲染,React 則在客戶端上實(shí)現(xiàn) hydration

          網(wǎng)絡(luò)
          內(nèi)容交付網(wǎng)絡(luò) (CDN)

          利用 CDN 可幫助我們實(shí)現(xiàn)內(nèi)容緩存,并加速其在全球范圍內(nèi)的交付速度。我們選擇了 Fastly.com,其目前處理著全球超過(guò) 10% 的請(qǐng)求總量,并得到 GitHub、Stripe、Airbnb 以及 Twitter 等諸多廠商的青睞。

          Fastly 允許我們編寫(xiě)定制化緩存,并可利用 VCL 配置語(yǔ)言建立路由邏輯。下面,我們將具體聊聊基礎(chǔ)請(qǐng)求流如何根據(jù)路由、請(qǐng)求頭等因素分步起效:

          VCL 請(qǐng)求流

          提高性能的另一個(gè)選項(xiàng)是配合 Fastly 在邊緣位置使用 WebAssembly(WASM)。大家可以將其視為一種無(wú)服務(wù)器模式,只是處于邊緣位置;所使用的語(yǔ)言則包括 C、Rust、Go 以及 TypeScript 等等。Cloudflare 就擁有一個(gè)類(lèi)似的項(xiàng)目,用于在 Workers 上支持 WASM。

          緩存

          盡可能多地利用緩存處理請(qǐng)求是改善性能水平的關(guān)鍵所在。立足 CDN 層級(jí)進(jìn)行緩存,將能夠更快地為新用戶提供響應(yīng)。而通過(guò)發(fā)送 Cache-Control 頭進(jìn)行緩存,則可加快瀏覽器中重復(fù)請(qǐng)求的響應(yīng)速度。

          大多數(shù)構(gòu)建工具(例如 Webpack)允許用戶向文件名當(dāng)中添加哈希值。由于指向這些文件的任何變更都會(huì)產(chǎn)生新的輸出文件名,因此大家可以安心將文件添加至緩存當(dāng)中。

          通過(guò) HTTP/2 進(jìn)行文件緩存與編碼

          GraphQL 緩存

          發(fā)送 GraphQL 請(qǐng)求的一種常見(jiàn)方法,就是利用 POST HTTP 方法。而我們選擇了立足 Fastly 層級(jí)對(duì)部分 GraphQL 請(qǐng)求進(jìn)行緩存:

          • 我們的 React 應(yīng)用會(huì)標(biāo)注出那些可進(jìn)行緩存的 GraphQL 查詢(xún)。

          • 在發(fā)送 HTTP 請(qǐng)求之前,我們以請(qǐng)求本體為基礎(chǔ)構(gòu)建一條附加 URL 參數(shù),其中包含 GraphQL 查詢(xún)與變量(我們配合 Apollo Client 使用自定義 fetch)。

          • 在默認(rèn)情況下 ,Varnish(與 Fastly)會(huì)使用完整的 URL 作為緩存密鑰的一部分。

          • 這意味著我們可以通過(guò)請(qǐng)求本體當(dāng)中的 GraphQL 查詢(xún)不斷發(fā)送 POST 請(qǐng)求,并在無(wú)需接觸服務(wù)器的前提下立足邊緣位置完成緩存。

          利用一條 SHA256 URL 參數(shù)發(fā)送 POST GraphQL 請(qǐng)求

          以下是其它一些值得參考的潛在 GraphQL 緩存策略:

          • 服務(wù)器端緩存:立足解析器層級(jí)或者通過(guò)模式標(biāo)注對(duì)全部 GraphQL 請(qǐng)求進(jìn)行緩存。

          • 利用持久化 GraphQL 查詢(xún)并發(fā)送 GET /graphql/:queryId 以使用 HTTP 緩存機(jī)制。

          • 利用自動(dòng)化工具(例如 Apollo Server 2.0)或者 GraphQL 專(zhuān)用型 CDN(例如 FastQL)實(shí)現(xiàn)不同 CDN 的整合。

          編碼

          目前,所有主流瀏覽器都支持利用 gzip 加 Content-Encoding 標(biāo)頭進(jìn)行數(shù)據(jù)壓縮。這意味著面向?yàn)g覽器的發(fā)送數(shù)據(jù)量更低,從而帶來(lái)更快的內(nèi)容傳遞速度。此外,如果瀏覽器支持,大家也可以嘗試使用效率更高的 brotli 壓縮算法。

          HTTP/2 協(xié)議

          HTTP/2 是 HTTP 網(wǎng)絡(luò)協(xié)議的新版本(DevConsole 中簡(jiǎn)稱(chēng)為 h2)。由于存在著以下幾項(xiàng)與 HTTP/1.x 版本間的顯著差別,切換至 HTTP/2 能夠帶來(lái)性能提升:

          • HTTP/2 為二進(jìn)制,而非文本式。因此其解析效率更高,也更加緊湊。

          • HTTP/2 具有多路復(fù)用屬性,這意味著 HTTP/2 可以通過(guò)單一 TCP 連接發(fā)送多項(xiàng)請(qǐng)求。如此一來(lái),我們就不必?fù)?dān)心每主機(jī)瀏覽器連接限制以及域名分片等問(wèn)題。

          • 其利用標(biāo)頭壓縮機(jī)制減少請(qǐng)求 / 響應(yīng)的實(shí)際體積。

          • 允許服務(wù)器主動(dòng)推送響應(yīng)。這項(xiàng)功能擁有諸多有趣的實(shí)際應(yīng)用方式。

          HTTP/2 Server Push

          由于給現(xiàn)有工具及生態(tài)系統(tǒng)(例如 rack)引入了一系列顛覆性的變更,很多編程語(yǔ)言與庫(kù)并不能完全支持 HTTP/2 的全部功能。但即便如此,我們?nèi)匀豢梢栽诓糠趾线m的場(chǎng)景中使用 HTTP/2。舉例來(lái)說(shuō):

          • 利用 HTTP/2 在常規(guī) HTTP/1.x 服務(wù)器之前設(shè)置一套 h2o 或者 nginx 代理服務(wù)器。Puma 與 Ruby on Rails 能夠發(fā)送 Early Hints,從而在一定的限制條件下啟用 HTTP/2 Server Push。

          • 利用支持 HTTP/2 的 CDN 交付靜態(tài)資產(chǎn)。例如,我們可以使用這種方法將字體以及一部分 JavaScript 文件推送至客戶端。

          HTTP/2 推送字體

          對(duì) JavaScript 以及 CSS 的推送功能同樣非常實(shí)用。但請(qǐng)注意不要過(guò)度推送,您可點(diǎn)擊此處了解一些相關(guān)問(wèn)題:https://jakearchibald.com/2017/h2-push-tougher-than-i-thought/

          瀏覽器中的 JavaScript
          包大小預(yù)算

          JavaScript 性能優(yōu)化中的頭號(hào)規(guī)則就是,不要使用 JavaScript。

          —— 我自己

          如果您已經(jīng)擁有現(xiàn)成的 JavaScript 應(yīng)用程序,那么設(shè)置預(yù)算規(guī)則能夠提高包大小的可見(jiàn)性,同時(shí)確保全部?jī)?nèi)容都可容納于同一頁(yè)面當(dāng)中。超出預(yù)算后,開(kāi)發(fā)人員則需要謹(jǐn)慎考慮并盡量防止規(guī)模進(jìn)一步增長(zhǎng)。以下是預(yù)算設(shè)置方面的相關(guān)示例:

          • 根據(jù)您的實(shí)際需求或推薦值設(shè)定數(shù)值。例如,不得大于 170 KB 否則壓縮 JavaScript。

          • 利用現(xiàn)有包大小作為基準(zhǔn),或者嘗試對(duì)其進(jìn)行削減——例如下調(diào) 10%。

          • 嘗試讓網(wǎng)站擁有高于競(jìng)爭(zhēng)對(duì)手的速度,并以此為依據(jù)設(shè)定預(yù)算。

          您可以使用 bundlesize 工具包或者 Webpack 性能提示與限制進(jìn)行預(yù)算跟蹤:

          Webpack 性能提示與限制

          消除依賴(lài)性

          Sidekiq 曾在一篇博文中提到:“代碼越少,運(yùn)行速度越快。代碼越少,bug 就越少。代碼越少,占用的內(nèi)存量就越低。代碼越少,理解起來(lái)就越輕松。”

          遺憾的是,實(shí)際 JavaScript 場(chǎng)景中往往存在著不計(jì)其數(shù)的依賴(lài)關(guān)系。您可以試試:ls node_modules | wc -l。

          在某些情況下,添加依賴(lài)性是種必然的選擇。在這種情況下,依賴(lài)性的包大小應(yīng)該被視為決定您實(shí)際工具包選擇的重要依據(jù)。我強(qiáng)烈建議大家使用 BundlePhobia:

          BundlePhobia 能夠提示將 npm 工具包添加至您數(shù)據(jù)包中帶來(lái)的實(shí)際成本

          代碼拆分

          使用代碼拆分是另一種能夠顯著提高 JavaScript 性能的好辦法。其本質(zhì)在于分解代碼片段并僅向用戶交付當(dāng)前所需要的部分。以下是關(guān)于代碼拆分的相關(guān)示例:

          • 在不同的 JavaScript 代碼塊間分別加載路由機(jī)制。

          • 拆分那些在頁(yè)面中無(wú)法立即顯示的部分,例如彈出框以及頁(yè)面下方的頁(yè)腳。

          • Polyfills 與 ponyfills 可支持全部主流瀏覽器當(dāng)中的各最新瀏覽器功能。

          • 利用 Webpack 的 SplitChunksPlugin 防止代碼重復(fù)。

          • 按需定位文件,以避免一次性發(fā)送所有受支持的語(yǔ)言。

          您可以利用 Webpack 動(dòng)態(tài)導(dǎo)入以及 React.lazy 配合 Suspense 實(shí)現(xiàn)代碼拆分。

          利用動(dòng)態(tài)導(dǎo)入以及 React.lazy 配合 Suspense 實(shí)現(xiàn)代碼拆分。

          相較于默認(rèn)導(dǎo)出,我們構(gòu)建的函數(shù)可取代 React.lazy 以支持點(diǎn)名導(dǎo)出。

          Async 與 defer 腳本

          目前,全部主流瀏覽器皆在 script 標(biāo)簽上支持 async 與 defer 屬性:

          加載JavaScript的不同方式

          幾種不同的 JavaScript 加載方式:

          • 內(nèi)聯(lián)腳本適用于加載小體積、高關(guān)鍵度 JavaScript 代碼。

          • 當(dāng)您的用戶或者任何其它腳本(例如分析腳本)不再需要某些特定腳本時(shí),大家可以將 async 與這些腳本配合使用以避免 HTML 解析阻塞。

          • 從性能角度來(lái)看,將 defer 與腳本配合使用能夠有效提升非關(guān)鍵 JavaScript 代碼的抓取與執(zhí)行效率,且避免發(fā)生 HTML 解析阻塞。此外,這種法還能夠在調(diào)用腳本時(shí)保證執(zhí)行順序,從而確保不同腳本間存在依賴(lài)性時(shí)實(shí)時(shí)與預(yù)期相符的執(zhí)行效果。

          來(lái)看 head 標(biāo)簽下不同腳本間的可視化差異:

          幾種不同的腳本抓取與執(zhí)行方式

          圖像優(yōu)化

          雖然與 100 KB 的圖像相比,100 KB 的 JavaScript 代碼明確會(huì)帶來(lái)更高的性能成本,但我們同樣有必要重視對(duì)圖像內(nèi)容的優(yōu)化調(diào)整。

          削減圖像大小的有效手段之一,是在適用的瀏覽器當(dāng)中采用更加輕量化的 WebP 圖像。對(duì)于那些無(wú)法支持 WebP 的瀏覽器,大家則可以采取以下幾種策略:

          • 回退至常規(guī)的 JPEG 或者 PNG 格式(某些 CDN 會(huì)根據(jù)瀏覽器的 Accept 請(qǐng)求標(biāo)頭自動(dòng)執(zhí)行)。

          • 在檢測(cè)瀏覽器的支持情況后,加載并使用 WebP polyfill。

          • 利用 Service Workers 監(jiān)聽(tīng) fetch 請(qǐng)求,并在支持時(shí)利用 WebP 變更實(shí)際 URL。

          WebP 圖像

          僅當(dāng)圖像位于視圖當(dāng)中或者附近時(shí)才進(jìn)行內(nèi)容加載,堪稱(chēng)多圖像初始頁(yè)面加載過(guò)程中效果最顯著的提速手段之一。您可以在受支持的瀏覽器當(dāng)中使用 IntersectionObserver 功能,也可以利用其它一些替代性工具實(shí)現(xiàn)相同的結(jié)果——例如 react-lazyload。

          在滾動(dòng)過(guò)程中進(jìn)行圖像的延遲加載

          其它一些圖像優(yōu)化策略還包括:

          • 降低圖像質(zhì)量以減小體積。

          • 調(diào)整大小并加載最小圖像。

          • 利用 Srcset 圖像屬性自動(dòng)在高分辨率顯示器上加載高質(zhì)量圖像。

          • 利用漸進(jìn)式圖像快速顯示圖像的模糊版本。

          常規(guī)圖像與漸進(jìn)圖像之間的加載效果差異

          大家也可以考慮使用通用型 CDN 或者圖像專(zhuān)用 CDN,其通常會(huì)直接提供與圖像相關(guān)的優(yōu)化功能。

          資源提示

          資源提示(Resource hints) 允許我們優(yōu)化資源交付、降低往返次數(shù),同時(shí)獲取資源以實(shí)現(xiàn)頁(yè)面瀏覽過(guò)程中的內(nèi)容交付提速。

          帶有 link 標(biāo)簽的資源提示

          • Preload 會(huì)在當(dāng)前頁(yè)面實(shí)際使用之前,通過(guò)后臺(tái)預(yù)先下載高優(yōu)先級(jí)資源。

          • Prefetch 的功能與 preload 類(lèi)似,用于抓取資源并進(jìn)行緩存,但僅供用戶后續(xù)導(dǎo)航使用(低優(yōu)先級(jí))。

          • Preconnect 允許 HTTP 請(qǐng)求被實(shí)際發(fā)送至服務(wù)器之前即設(shè)置預(yù)連接。

          提前進(jìn)行預(yù)連接以避免 DNS、TCP 以及 TLS 往返延遲

          當(dāng)然,prerender 以及 dns-prefetch 等其它一些資源提示同樣非常重要。其中一部分資源提示可在響應(yīng)標(biāo)頭中進(jìn)行指定。需要提醒大家的是,請(qǐng)務(wù)必小心使用資源提示。一旦開(kāi)始濫用,您的頁(yè)面中可能包含大量不必要的請(qǐng)求并快速下載過(guò)量數(shù)據(jù),這種情況顯然不利于使用蜂窩數(shù)據(jù)的移動(dòng)用戶。

          總結(jié)

          應(yīng)用程序的性能改善之路代表著一個(gè)永遠(yuǎn)盡頭的過(guò)程,且通常要求我們?cè)谡麄€(gè)堆棧當(dāng)中持續(xù)作出更改。

          每次看到下面這段視頻,我總會(huì)想起你們努力減少應(yīng)用包大小的樣子。

          ——我的同事

          馬上把一切不需要的東西從飛機(jī)上扔下去!——電影《珍珠港》

          以下列出了我們已經(jīng)使用或者計(jì)劃嘗試的其它一些潛在性能改進(jìn)思路:

          • 使用 Service Workers 進(jìn)行緩存、離線支持以及主線程分?jǐn)偂?/p>

          • 通過(guò)關(guān)鍵 CSS 內(nèi)聯(lián)或者函數(shù)式 CSS 實(shí)現(xiàn)數(shù)據(jù)包的長(zhǎng)效“瘦身”。

          • 使用 WOFF2 字體替代 WOFF 字體(僅舉一例,字體變更最高可帶來(lái) 50% 壓縮效果)。

          • 確保 browserslist 的定期更新。

          • 利用 webpack-bundle-analyzer 直觀分析構(gòu)建塊。

          • 優(yōu)選較小的工具包(例如 date-fns)及插件(例如 lodash-webpack-plugin),從而縮小頁(yè)面體積。

          • 嘗試使用 preact、lit-html 或者 svelte。

          • 在 CI 中運(yùn)行 Lighthouse。

          • 漸進(jìn)式 hydration 與 React 流式設(shè)計(jì)。

          另外還有更多令人興奮的想法可供嘗試。希望本文提出的信息及以下案例研究能夠激發(fā)出大家改善應(yīng)用程序性能的更多靈感:

          • 根據(jù)亞馬遜方面的計(jì)算,單一頁(yè)面 1 秒的響應(yīng)延時(shí)每年可能造成 16 億美元損失。鏈接地址:https://www.fastcompany.com/1825005/how-one-second-could-cost-amazon-16-billion-sales

          • 沃爾瑪每縮短 1 秒加載時(shí)長(zhǎng),即可提升 2% 的客戶轉(zhuǎn)換率。每 100 毫秒的提升則可帶來(lái) 1% 的收入增長(zhǎng)。鏈接地址:https://wpostats.com/2015/11/04/walmart-revenue.html

          • 谷歌公司計(jì)算出,如果搜索結(jié)果顯示速度減緩 0.4 秒,則每天搜索量將減少 800 萬(wàn)次。鏈接地址:https://www.fastcompany.com/1825005/how-one-second-could-cost-amazon-16-billion-sales

          • 品趣志的頁(yè)面重構(gòu)將等待時(shí)長(zhǎng)縮短了 40%,SEO 流量增加了 15%,注冊(cè)轉(zhuǎn)換率亦提升 15%。鏈接地址:https://medium.com/@Pinterest_Engineering/driving-user-growth-with-performance-improvements-cfc50dafadd7

          • BBC 通過(guò)觀察發(fā)現(xiàn),網(wǎng)站加載時(shí)長(zhǎng)每增加 1 秒鐘,就會(huì)失去 10% 的用戶。鏈接地址:https://www.creativebloq.com/features/how-the-bbc-builds-websites-that-scale

          • FT.com 通過(guò)測(cè)試證明,更快的響應(yīng)速度令用戶的參與度提高了 30%——這意味著更多的訪問(wèn)次數(shù)與更大的內(nèi)容消費(fèi)總量。鏈接地址:https://www.wsj.com/articles/financial-times-hopes-speedy-new-website-will-boost-subscribers-1475553602

          • Instagram 通過(guò)降低顯示評(píng)論內(nèi)容所需的 JSON 響應(yīng)包的大小,成功將展示次數(shù)與用戶個(gè)人資料滾動(dòng)操作量增加了 33%。鏈接地址:https://instagram-engineering.com/performance-usage-at-instagram-d2ba0347e442


          來(lái)源:前端之巔
          作者:exAspArk
          譯者:核子可樂(lè)
          原文:https://engineering.universe.com/improving-browser-performance-10x-f9551927dcff?gi=ef65642ac481
          瀏覽 59
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  豆花视频一区二区三区在线观看 | 一道本一区二区三区久久久久 | av电影久久 | 老司机无码视频 | 翔田千里在线激情视频 |