關於前端性能優化你瞭解多少?不少人都知道雅虎軍規,可是你知道爲何嗎?javascript
Vitaly Friedman寫了一篇關於前端性能優化的清單,裏面引用了至少六七百篇參考連接,詳細介紹了前端性能優化相關知識,強烈建議你們好好閱讀一下,包括引用的文章。英語閱讀有困難的,去年京東的WecTeam團隊也針對此篇文件進行了翻譯,固然,那是去年的版本了。前端
Front-End Performance Checklist 2021[1]
https://www.smashingmagazine....
我學到了不少,但願你也同樣,若有任何錯誤歡迎指出。java
性能優化,優化到什麼程度,標準是什麼?react
● 至少比你最快的競爭對手快20% ● 最大內容繪製(LCP)控制在2.5s內 ● 首屏展示平均值(SI)控制在3s內 ● 首次輸入延時(FID)控制在100ms內 ● 累計阻塞時長(TBT)控制在300ms內 ● 累積佈局變化量(CLS)控制在0.1內
研究代表,只有當你的頁面比你的競爭對手快至少20%時,用戶才能真正感知到你的頁面真的比競爭對手的頁面快。git
與競爭對手相比,若是你的頁面加載時長是5s,而競爭對手的是2s,就算你提高了20%也是不行的,這個時候就須要與競爭對手做比較。若是咱們作不到優化到2s,那咱們至少要優化到2s + 2 * 20% = 2.4s,這樣至少用戶不會感知到差別。github
若是2.4s也作不到,這裏還有一個心理閥值。以剛剛的2s、5s爲例,大於此閾值的持續時間將被用戶感知爲接近5秒。持續時間小於該閾值的持續時間將被視爲接近2秒。經過這種概念,咱們能夠找到它的一個幾何平均值:√(A × B),例子中就是:√(2 × 5) ≈ 3.2 seconds,若是加載時間小於3.2s,用戶能注意到差別,可是這對他們來講此差別對他們如何選擇服務並不重要。web
LCP是一個頁面加載時長的技術指標,用於表示當前頁面中最重要/佔比最大的內容顯示出來的時間點。LCP低於2.5s則表示頁面加載速度優良。shell
爲了計算最大的元素,LCP會考慮如下元素:瀏覽器
● <img>, <image> or <video> elements ● Elements with background images. E.g: background-image: url() ● Block level elements containing text
計算方式緩存
可以使用Largest Contentful Paint API
new PerformanceObserver((entryList) => { for (const entry of entryList.getEntries()) { console.log('LCP candidate:', entry.startTime, entry); } }).observe({type: 'largest-contentful-paint', buffered: true});
還可以使用第三方庫web-vitals
import { getLCP } from 'web-vitals'; // 能夠發送到監控系統 getLCP(console.log);
爲了衡量用戶感知頁面加載進度的關鍵時間,咱們還有一些其餘的指標,但都多多少少有些缺陷:
指標 | 定義 | 缺點 |
---|---|---|
首次內容渲染(FCP)First Contentful Paint | 瀏覽器呈現第一塊DOM內容的時間 | 一般與用戶無關(如:loading、導航欄) |
首次有效渲染(FMP)First Meaningful Paint | 在頁面加載期間,計算的最大的佈局更改後的繪製時間 | 一、沒有標準化,很難跨瀏覽器實現;二、大約20%的狀況不許確與SI相比,它更容易理解,與SI的結果類似,且在RUM工具中更易於計算和報告。 |
影響因素:緩慢的服務器響應時間,阻塞的CSS、JavaScript,網頁字體加載,昂貴的渲染或繪畫操做,延遲加載的圖像,骨架屏幕或客戶端渲染
優化方式:
● 消除阻塞渲染資源 ● 經過加載具備正確優先級和正確順序的資源來最小化關鍵請求鏈 ● 壓縮圖像,併爲不一樣的設備提供不一樣的圖像大小 ● 經過最小化文件和提取關鍵的CSS來優化CSS ● 使用字體加載策略來避免不可見文本(FOIT)的閃現
LCP評分低的主要緣由一般是圖像。要在Fast 3G上以小於2.5s的速度交付LCP——託管在一個優化良好的服務器上,全部靜態的沒有客戶端渲染,而且有一個來自專用圖像CDN的圖像——意味着最大的理論圖像大小隻有大約144KB。這就是爲何響應式圖像很重要,以及提早預加載關鍵圖像(使用預加載)的緣由。
在DevTools中,你能夠將鼠標懸停在Performance面板「Timing」下的LCP欄上,以發現什麼元素觸發了LCP。
Speed Index是衡量頁面性能的指標,顯示頁面的可見部分的平均時間。該值越低越好,SI低於3s則表示頁面加載速度良好。
計算方式:須要可以計算在頁面加載期間,各個時間點「完成」了多少部分。在WebPagetest中,經過捕獲在瀏覽器中加載頁面的視頻並檢查每一個視頻幀(在啓用視頻捕獲的測試中,每秒10幀)來完成的。計算比較複雜,有興趣的同窗能夠翻閱資料。
它是一個複雜的指標,不容易解釋;且計算密集,因此它不能用於任何主流瀏覽器的真實用戶監控(RUM)。
優化方式:
● 優化內容效率:消除沒必要要的下載,使用壓縮技術優化每一個資源的傳輸編碼,儘量利用緩存消除冗餘下載 ● 優化關鍵渲染路徑:只加載當前頁面渲染所需的必要資源,將次要資源放在頁面渲染完成後加載
注意,隨着LCP成爲一個更相關的指標,它變得不那麼重要了。
FID衡量的是用戶第一次與頁面交互到頁面真正響應的時間。注:滾動與縮放不包括在此指標中。延時越長,用戶體驗越差,最好控制在100ms內。減小頁面初始化時間,消除長任務能夠有效幫助消除首次輸入延時。
計算方式:
可使用Event Timing API
new PerformanceObserver((entryList) => { for (const entry of entryList.getEntries()) { const delay = entry.processingStart - entry.startTime; console.log('FID candidate:', delay, entry); } }).observe({type: 'first-input', buffered: true});
還可藉助第三方庫web-vitals
import { getFID } from 'web-vitals'; // 能夠發送到監控系統 getFID(console.log);
優化方式:
● 分解長任務 ● 使用 Web Worker ● 減小JS執行時間 ● 優化數據獲取 ● 延遲第三方腳本執行 ● 在SPA中採用漸進式注水
簡單來講,得到更好的FID分數的可靠策略是將主線程上的工做最小化,方法是將較大的捆綁包分解成較小的捆綁包,並在用戶須要時爲其提供服務,這樣用戶交互就不會被延遲。
TBT是一個衡量用戶事件響應的指標。TBT會統計在FP和TTI時間之間,主線程被阻塞的時間總和。當主線程被阻塞超過50ms致使用戶事件沒法響應,這樣的阻塞時長就會被統計到TBT中。TBT越小說明頁面可以更好的快速響應用戶事件。當頁面TBT在300ms內時被認爲良好,若是超過600ms則被認爲慢了。
計算方式:統計任務超過50ms部分,以下圖,3個任務,分別執行了120ms、30ms、75ms,總的TBT是95ms。
優化方式:
● 對JavaScript包進行代碼拆分,並延遲加載那些對初始加載不重要的包 ● 在可能的狀況下,將代碼分解成工做更少、執行更快的函數 ● 減小過多的DOM查詢 ● 將計算密集型任務卸載給Service Worker或Web Worker
CLS是一個衡量頁面內容是否穩定的指標,量化了頁面加載期間viewport內移動的元素數量,幫助肯定頁面上發生意外移動的頻率。CLS的分數越低,代表頁面的佈局穩定性越高,一般低於0.1表示頁面穩定性良好。
計算方式:CLS = 距離分數 * 衝擊分數
● 距離分數:不穩定元素移動的距離 ● 衝擊分數:受不穩定元素影響的視口表面積
如:元素向下移動了三分之一的視口高度,因此距離分數爲0.33,元素在初始位置和移動後佔據的區域構成了視口表面的⅔,因此影響分數是0.66。因此,佈局移位得分爲0.33 × 0.66 = 0.2178。
可以使用Layout Instability API
let cls = 0; new PerformanceObserver((entryList) => { for (const entry of entryList.getEntries()) { if (!entry.hadRecentInput) { cls += entry.value; console.log('Current CLS value:', cls, entry); } } }).observe({type: 'layout-shift', buffered: true});
還能夠藉助第三方庫web-vitals
import {getCLS} from 'web-vitals'; // Measure and log CLS in all situations // where it needs to be reported. getCLS(console.log);
影響因素:後備字體和web字體有不一樣的字體指標,或廣告,嵌入或iframes來晚了,或圖像/視頻尺寸沒有保留,或晚期CSS強制重繪,或更改被晚期JavaScript注入。
優化方式:
● img元素:添加寬度和高度屬性 ● 廣告:提早定義廣告空間的尺寸 ● 動態內容:使用內容佔位符,這樣一旦真正的內容加載,佈局就不會發生劇烈變化 ● 動畫:使用transform屬性 ● 具備font-display: swap屬性的web字體:頁面佈局一般會在web字體加載和替換回退字體時發生變化,由於它們之間的大小不一樣,要避免這個問題,請使用字體樣式匹配器選擇具備類似尺寸的後備字體
TTI度量主線程有5秒沒有網絡活動或JavaScript長任務的時間,長任務指耗時超過50ms的JavaScript任務。在這個時間點上,佈局已經穩定,關鍵的webfonts是可見的,而且主線線程已經足夠處理用戶輸入-基本上是用戶能夠與UI交互的時間標記。是瞭解用戶在使用站點時要經歷多少等待而沒有延遲的關鍵指標。它主要標識主線程什麼時候空閒,而TBT量化主線程在空閒以前的繁忙程度。
良好的頁面性能須要在慢3G中TTI要控制在5s內,二次訪問時TTI控制在2s內。
計算方式:最簡單的方式是經過 Performation Api。
const timing = performance.timing const TTI = timing.loadEventEnd - timing.navigationStart
優化方式:
● 最小化主線程工做 ● 減小JavaScript執行時間
注意:FID和TTI都不考慮滾動行爲;滾動能夠獨立發生,由於它是非主線程。
谷歌推薦一系列可接受的速度目標,至少75%的頁面瀏覽量應該超過「良好」範圍,才能經過這個評估。這些指標迅速得到了關注,並在2021年5月成爲谷歌搜索的排名信號
一、LCP < 2.5s on Fast 3G
二、FID < 100ms
三、CLS < 0.1
爲了讓交互感受流暢,頁面響應用戶的輸入動做最好小於100ms。
爲了達到<100毫秒的響應時間,頁面必須每隔<50毫秒將控制權交還給主線程。輸入延遲能夠告訴咱們是否達到該閾值,理想狀況下,它應該低於50ms。對於像動畫這樣的敏感點,最好在你執行動畫的時候什麼都不作。
另外,動畫的每一幀都應在16毫秒內完成,從而達到每秒60幀(1秒÷60 = 16.6毫秒)- 因爲瀏覽器須要時間才能在屏幕上繪製新的幀,而你的代碼應在16.6毫秒以前完成執行,因此最好在10毫秒之內。
雖然很難實現,但一個好的目標是將TTI控制在5s內,二次訪問時,將TTI控制在2s內。LCP的目標是2.5s如下,同時最大限度地減小TBT和CLS。一個能夠接收的FID須要控制在100-70ms內。
爲了網絡快速傳輸內容,有2個限制因素。一方面因爲TCP慢啓動,咱們受網絡傳輸限制:HTML的前14KB是最關鍵的有效傳輸塊,而且是內容中惟一能夠在第一次網絡往返就傳輸完成的部分( 加上移動網絡喚醒時間的緣由,這就是您在RTT爲400ms網絡的環境下在1s內能得到的最多內容)。另外一方面,因爲JavaScript解析須要時間,咱們在內存和CPU方面存在硬件限制,爲了實現咱們的目標,必須考慮JS關鍵文件大小,壓縮到170KB JavaScript的文件已經須要花費了1s才能在普通手機上進行解析和編譯。假設170KB的文件在解壓縮時擴展到原來的3倍(0.7MB),那在Moto G4 / G5 Plus上這類機型上就已經很大達到「體面的」用戶體驗了。針對懶加載路由,Addy Osmani也建議控制在35KB之內。
注:爲何是14KB?當TCP啓動時,它容許發送10個TCP包,而後它們必須被確認。當這些數據包被確認後,它就容許發送更多的數據包,加倍後容許下一次發送20個數據包,而後是40個,而後是80個……隨着它逐漸創建到網絡能夠處理的所有容量。14kb的神奇數字是由於每一個TCP包最多能夠有1500個字節,可是其中40個字節是留給TCP使用的(TCP頭等),剩下1460個字節留給實際數據。其中的10個數據包意味着您能夠交付14600字節或大約14kb(其實是14.25 KB)。固然,這都是理論上的,實際如何有興趣的能夠閱讀博客[8]。
爲了收集準確的數據,咱們須要完全全面地選擇要測試的設備。
根據IDC的數據,到2020年,全球84.8%的手機出貨量爲Android設備。普通消費者每兩年更換一次手機,而美國的手機更換週期是33個月。全球最暢銷手機的平均售價不到200美圓。
那麼,一個表明性的設備,是一個Android設備,至少用了24個月,價格爲200美圓或更少,運行在緩慢的3G, 400ms RTT和400kbps傳輸。固然,這比較悲觀了。雖然這多是符合大部分的用戶,但咱們仍是要以公司實際的客戶爲準。
針對以上狀況,在開放式設備實驗室中,咱們能夠選擇稍老一點的Moto G4/G5 Plus,中檔三星設備(Galaxy A50, S8),不錯的中檔設備,如Nexus 5X,小米Mi A3或小米紅米Note 7,以及速度較慢的設備,如阿爾卡特1X或Cubot X19。若是你想在較慢的熱調節設備上測試,你也能夠買一臺Nexus 4,價格僅爲100美圓左右。
此外,檢查每一個設備使用的芯片組,機型組合不要過分集中在一個芯片組中: 建議包含幾代的驍龍CPU(Snapdragon)和蘋果CPU(Apple)以及低端的Rockchip、聯發科(Mediatek)
若是您手頭沒有設備,能夠先在在臺式機上模擬移動體驗:節流的3G網絡(例如300ms RTT、1.6 Mbps下行、0.8 Mbps上行)和CPU限速(減速5倍)上進行測試。最終切換到常規3G、低速4G(例如170ms RTT、9 Mbps下行、9 Mbps上行)和Wi-Fi。
不要過於關注那些被認爲很酷的工具,堅持在你的開發流程中進行構建優化,不管是Grunt、Gulp、Webpack、Parcel仍是這些工具的組合。只要得到了想要的結果,而且維護構建過程沒有問題,那就足夠了。
在全部構建工具中,Rollup不斷得到關注,Snowpack也同樣,但Webpack彷佛是最成熟的一個,它有數百個插件可用來優化構建的大小。查看Webpack 2021路線圖。若是想了解更多Webpack,能夠閱讀原文,提供了一系列學習資源。
因爲有很是多的未知因素影響加載性能-網絡、負載均衡、緩存覆蓋、第三方腳本、解析器阻塞模式、磁盤I/O、IPC延遲、安裝的擴展、防病毒軟件和防火牆、後臺CPU任務、硬件和內存限制、二級/三級緩存的差別、RTTS。JavaScript是其中影響最多、成本最高的,僅次於默認狀況下阻止頁面呈現的Web字體和常常消耗太多內存的圖像。
以前提到的170KB的預算已經包含關鍵路徑HTML/CSS/JavaScript、路由器、狀態管理、實用程序、框架和應用程序邏輯,因此咱們必須完全檢查咱們選擇的框架的網絡傳輸成本、解析/編譯時間和運行時成本。
如今,不是每一個web應用都須要前端框架,在單頁應用程序中也不是每一個頁面都須要加載框架。在Netflix的場景中,「從客戶端刪除React,一些第三方庫和相應的應用程序代碼能夠將JavaScript的總量減小200KB以上,從而使Netflix首頁登陸的可互動時間減小了50%以上。」而後,該團隊利用用戶在登陸頁面上花費的時間來預取React,這樣作在用戶可能訪問的後續頁面中就不用繼續加載React了。
一旦選擇好了框架,咱們一般會至少使用幾年,因此必定要確保咱們的選擇是瞭解並通過深思熟慮的。
數據代表,框架自己就至關昂貴:58.6% 的React 頁面JavaScript超過1 MB, 36% 的Vue.js 頁面加載FCP小於1.5s。根據Ankur Sethi研究結果:"在印度,React應用程序不管你怎麼優化,在普通手機上加載速度都不可能超過1.1s,Angular應用程序須要花至少2.7s才能完成啓動,Vue應用程序須要用戶至少等待1s才能開始使用。雖然印度並不是你的主要市場,可是使用次優網絡添加訪問你網站的用戶會有相似的體驗。
若是選擇框架?至少要考慮框架的大小以及框架的初始執行時間。Seb Markbège指出,衡量框架啓動成本的一個好方法是先渲染視圖,而後刪除視圖再二次渲染,這樣就能夠知道框架繪製的成本。所以首次渲染視圖以前每每須要預熱一堆延遲編譯的代碼,更大DOM樹在繪製時受益更多。二次渲染則是模擬頁面上的代碼複用度是如何隨着頁面複雜度的增長而影響性能特徵。
Sacha Greif的12分制評分系統[9]也可幫助你評估一個框架(或任何JavaScript庫)包括:探索特性、可訪問性、穩定性、性能、包生態系統、社區、學習曲線、文檔、工具、跟蹤記錄、團隊、兼容性、安全性等。還能夠依賴Perf Track[10],長期大規模跟蹤框架性能,收集Angular,React,Vue,Polymer,Preact,Ember,Svelte和AMP在構建的網站的原始彙總的Core Web Vitals分數。
最終的方法是設置某種漸進式引導:使用服務端渲染來得到一個快速的FCP,但也包括一些必要的JS來保持TTI接近FCP。若是JS在FCP以後出現得太晚,瀏覽器將在解析、編譯和執行遲發現的JS時鎖定主線程,從而限制站點或應用程序的交互性。爲了不此類問題發生,將任務劃分爲獨立、異步的,能夠考慮使用import()動態加載的方式,只有在用戶真正須要時纔去加載、解析、編譯。
關於渲染方式,咱們有幾種選擇:
● Full Server-Side Rendering (SSR)
全部請求都在服務器上完成。相似之前的JSP、PHP。
優勢:請求的內容做爲完成的HTML頁面返回,瀏覽器能夠當即呈現它。由於HTML是流到瀏覽器,FCP和TTI之間的差距一般很小。因爲它是在瀏覽器得到響應以前處理的,同時避免了客戶端數據獲取和模板的額外往返。
缺點:SSR應用程序不能真正利用DOM API;服務器響應時間較長,沒有利用現代應用程序的響應性和豐富的特性。
● Static Rendering
構建時發生,單頁應用程序,全部頁面都預先呈現爲靜態HTML,構建步驟中使用最少的JS。
優勢:頁面的HTML不須要動態生成,服務器響應時間快,能夠快速獲取第一個字節。
缺點:必須爲每一個可能的URL生成單獨的HTML文件。當你沒法提早預測是哪些URL時或用於具備大量獨特頁面的站點時,這可能具備挑戰性,甚至是不可行的。
● Server-Side Rendering With (Re)Hydration (Universal Rendering, SSR + CSR)
一次呈現多個請求,將生成內容時以塊的形式發送內容。(服務器將應用程序呈現爲HTML,而後在客戶端上請求JavaScript和用於呈現的數據再次渲染來「修補」 。)
優勢:得到客戶端應用的徹底靈活性,同時提供更快的服務器端渲染,改進了First Paint。因爲使用了SSR,全部也有其優勢,實現快速的FCP。
缺點:FCP與TTI之間產生更長的間隔,同時增長了FID。SSR的頁面一般看起來具備欺騙性,在執行客戶端JS並附加事件處理程序以前,沒法響應輸入。
● Streaming Server-Side Rendering With Progressive Hydration (SSR + CSR)
與上一個相似,內容以流式形式生成併發送。
優勢:沒必要等待完整的HTML字符串後再將內容發送到瀏覽器,所以改進了Time to First Byte。在客戶端,採用逐步啓動組件,減小FID與TTI,同時縮小FCP與TTI直接的間隔。
● Trisomorphic Rendering
爲初始/非js導航提供流服務器渲染,而後讓service worker在安裝後爲導航提供HTML渲染。
● CSR With Prerendering
預渲染相似於服務器端呈現,但不是在服務器上動態呈現頁面,而是在構建時將應用程序渲染爲靜態HTML。它在構建時將客戶端應用程序的初始狀態捕獲爲靜態HTML,而預渲染應用程序必須在客戶端上啓動,以便頁面是交互式的。
優勢:更好的Time To First Byte和FCP,減小了TTI和FCP之間的差距。
缺點:若是預期內容會有很大變化,咱們就不能使用這種方法。另外,必須提早知道全部url才能生成全部頁面。
● Full Client-Side Rendering (CSR)
使用JavaScript在瀏覽器中直接渲染頁面。全部邏輯,數據獲取,模板和路由都在客戶端而不是服務器上處理。
缺點:TTI與FCP差距較大。因爲整個應用程序必須在客戶端上啓動才能呈現內容,因此整個應用程序會比較慢。隨着應用程序的增加,所需的JavaScript數量趨於增加。
總的來講,SSR比CSR要快,僅僅只是SSR,或僅僅只是CSR都不是一個好的方式,最好是結合二者。若是您的頁面變化不大,請考慮預渲染,並儘量推遲框架的啓動。使用服務器端呈現的HTML塊流,併爲客戶端呈現實現按部就班的水化——並在可見性、交互或空閒時間水化,以得到二者的最佳效果。
固然,若是能夠,咱們仍是須要儘量的靜態化,提早預構建更多的內容,而不是在請求時在服務器或客戶端上生成頁面視圖,咱們將得到更好的性能。
另外,還能夠考慮使用PRPL模式和骨架屏,其想法很是簡單:將實現初始路由交互所需的最小代碼推入,以便快速呈現,而後使用service worker緩存和預緩存資源,而後異步地惰性加載所需的路由。
咱們預先構建的內容越多,而不是在請求時在服務器或客戶端上生成頁面視圖,咱們將得到更好的性能。
PRPL模式[12]
它描述一種用於使網頁加載並變得交互式,更快的模式:
● 推送(或預加載)最重要的資源。 ● 儘快渲染初始路線。 ● 預緩存剩餘資產。 ● 延遲加載其餘路由和非關鍵資產。
App Shell 架構[13]
是支持用戶界面的最小HTML,CSS和JavaScript。App Shell架構應:
● 快速加載 ● 被緩存 ● 動態顯示內容
GraphQL[14]是API的一種查詢語言,而且是服務器端運行時的,用於經過使用爲數據定義的類型系統執行查詢。與REST不一樣,GraphQL能夠在單個請求中檢索全部數據,而且只響應所需的內容,而不會像REST一般那樣過分或不足地獲取數據。
此外,由於GraphQL使用模式(schema,定義數據結構的元數據),因此它能夠提早將數據組織成所需的結構,所以使用GraphQL,咱們能夠刪除用於處理狀態和數據結果的JavaScript代碼,從而產生在客戶端上運行更快更乾淨的應用程序代碼。
AMP[15]:是一個Web組件框架,可輕鬆爲Web建立用戶至上的體驗。
Instant Article[16]:一種原生格式,可供發行商建立加載迅速的 Facebook 互動式文章。
Apple News[17]: 是專業新聞出版物的平臺。
仔細檢查你的CDN是否支持執行壓縮和轉換(例如,圖像優化和調整大小),是否爲Service Worker提供支持,A/B測試,將在CDN層面組合頁面的靜態和動態部分(距離用戶最近的服務器)以及其餘支持的特性。此外,檢查你的CDN是否支持HTTP over QUIC(HTTP/3)。
如何選擇CDN,能夠參考Katie Hempenius關於CDN的指導[18]。一般,最好是儘量積極地緩存內容並啓用CDN性能功能(如Brotli,TLS 1.3,HTTP / 2和HTTP / 3)。原文還有不少關於CDN比較的網站,有興趣的也能夠看一下。
歡迎關注個人我的公衆號:
參考資料
Front-End Performance Checklist 2021[1]:https://www.smashingmagazine....
Why Perceived Performance Matters, Part 1: The Perception Of Time[2]:https://www.smashingmagazine....
Largest Contentful Paint (LCP)[3]:https://web.dev/lcp/
First Input Delay[4]:https://web.dev/fid/
Total Blocking Time (TBT) [5]:https://web.dev/tbt/
Cumulative Layout Shift (CLS)[6]:https://web.dev/cls/
Web Vitals[7]:https://web.dev/vitals/
web-vitals library:https://github.com/GoogleChro...
Optimize for Core Web Vitals:https://www.youtube.com/watch...
Critical Resources and the First 14 KB[8]:https://www.tunetheweb.com/bl...
12-point scale scoring system[9]:https://www.freecodecamp.org/...
Perf Track[10]:https://perf-track.web.app/
Rendering on the Web[11]:https://developers.google.com...
PRPL pattern[12]:https://web.dev/apply-instant...
App shell architecture[13]:https://developers.google.com...
GraphQL[14]:https://graphql.org/
AMP[15]:https://amp.dev/
Instant Articles[16]:https://www.facebook.com/form...
Apple News[17]:https://developer.apple.com/n...
Content delivery networks (CDNs)[18]:https://web.dev/content-deliv...