Categories
程式開發

JQuery、Vue、React、Angular,JavaScript框架成本終極對比


本文最初發佈於 Tim Kadlec 博客,經原作者授權由 InfoQ 中文站翻譯並分享。

想要減慢網站的速度,最快的辦法就是塞進去一堆 JavaScript 代碼了。

JavaScript 的問題是,到最後你要繳納至少四次性能稅:

  1. 在網絡上下載文件的成本
  2. 下載後解析和編譯未壓縮文件的成本
  3. 執行 JavaScript 的成本
  4. 內存成本

這種組合非常昂貴:

https://v8.dev/blog/cost-of-javascript-2019

而且我們用的 JS 代碼數量越來越多。隨著組織紛紛轉向由 React、Vue.js 等類似框架驅動的網站,我們網站的核心功能越來越依賴 JavaScript。

我看到很多非常笨重的網站都在使用它們,但由於與我合作的公司之所以來找我,恰恰是因為他們正面臨著性能挑戰,所以我的觀點是帶有很大偏見的。我很好奇這種情況有多普遍,以及當我們將這些框架作為默認起點時要付出多少代價。

感謝 HTTP Archive,有了它我們就可以搞清楚這一點了。

數據

HTTP Archive 總共跟踪 4,308,655 個桌面網址和 5,484,239 個移動網址。在 HTTP Archive 針對這些網址報告的諸多數據點中,有一個針對給定站點的檢測到的技術列表。這意味著我們可以找出幾千個使用各種框架的網站,並查看它們所交付的代碼量及 CPU 的成本消耗。

我查詢了 2020 年 3 月(撰文時的最近一期)這一期的所有數據。

我決定將 HTTP Archive 記錄的所有站點的匯總數據與檢測到 React、Vue.js 和 Angular 的站點進行比較。[注 1]

為了加點樂趣,我還添加了 jQuery(它仍然非常流行)。與 React、Vue.js 和 Angular 提供的單頁應用程序(SPA)方法相比,它還代表了另一種使用 JavaScript 構建的方式。

HTTP Archive 中檢測到的具有特定框架的網站

框架:jQuery

移動網站:4,615,474

桌面網站:3,714,643

框架:React

移動網站:489,827

桌面網站:241,023

框架:Vue.js

移動網站:85,649

桌面網站:43,691

框架:Angular

移動網站:19,423

桌面網址:18,088

希望和夢想

在我們深入研究之前,先說一下我的期望。

在理想的世界中,我認為框架應該超越開發人員的經驗價值,並為使用我們網站的人們提供具體的價值。性能只是其中的一部分——可訪問性和安全性也都是應該考慮的——但性能是很關鍵的部分。

因此在理想的世界中,框架可以提供更好的起點或提供一些限制條件和特徵,讓開發人員難以構建性能不佳的事物,從而幫助開發人員更容易地實現良好的性能。

最好的框架可以兼顧上面兩點:提供更好的起點,並幫助開發人員限制事物,防止失控。

只查看我們數據的中位數的話是看不出來這些的,實際上這種方式會遺漏大量信息:

https://timkadlec.com/remembers/2018-06-07-prioritizing-the-long-tail-of-performance/

所以對於每組統計數據,我會提取以下百分點:第 10、25、50(中位數),75 和 90。

第 10 和第 90 個百分點對我來說特別有趣。對於給定的框架,第 10 個百分點代表同類最佳(或至少可以說是接近同類最佳)。換句話說,在使用給定框架的所有站點中,只有 10%達到或超過這一門檻。另一方面,第 90 個百分點恰恰相反:它向我們展示了情況能變得有多糟糕。第 90 個百分點代表長尾,也就是體積最大或主線程耗時最多的最後 10%的站點。

JavaScript 字節數

首先,應該檢查的是通過網絡傳遞的 JavaScript 字節數(體積)。 10% 的百分點代表數據集的數據由好到差排序時,排在第 10% 的站點數據,以此類推。

向移動設備傳輸的 JavaScript 體積,按百分點排序

數據集:所有站點

傳輸大小,10%:93.4kb

傳輸大小,25%:196.6kb

傳輸大小,50%:413.5kb

傳輸大小,75%:746.8kb

傳輸大小,90%:1,201.6kb

數據集:使用 jQuery 的站點

傳輸大小,10%:110.3kb

傳輸大小,25%:219.8kb

傳輸大小,50%:430.4kb

傳輸大小,75%:748.6kb

傳輸大小,90%:1,162.3kb

數據集:使用 Vue.js 的站點

傳輸大小,10%:244.7kb

傳輸大小,25%:409.3kb

傳輸大小,50%:692.1kb

傳輸大小,75%:1,065.5kb

傳輸大小,90%:1,570.7kb

數據集:使用 Angular 的站點

傳輸大小,10%:445.1kb

傳輸大小,25%:675.6kb

傳輸大小,50%:1,066.4kb

傳輸大小,75%:1,761.5kb

傳輸大小,90%:2,893.2kb

數據集:使用 React 的站點

傳輸大小,10%:345.8kb

傳輸大小,25%:441.6kb

傳輸大小,50%:690.3kb

傳輸大小,75%:1,238.5kb

傳輸大小,90%:1,893.6kb

JQuery、Vue、React、Angular,JavaScript框架成本終極對比 1

向桌面設備傳輸的 JavaScript 體積,按百分點排序

數據集:所有站點

傳輸大小,10%:105.5kb

傳輸大小,25%:226.6kb

傳輸大小,50%:450.4kb

傳輸大小,75%:808.8kb

傳輸大小,90%:1,267.3kb

數據集:使用 jQuery 的站點

傳輸大小,10%:121.7kb

傳輸大小,25%:242.2kb

傳輸大小,50%:458.3kb

傳輸大小,75%:803.4kb

傳輸大小,90%:1,235.3kb

數據集:使用 Vue.js 的站點

傳輸大小,10%:248.0kb

傳輸大小,25%:420.1kb

傳輸大小,50%:718.0kb

傳輸大小,75%:1,122.5kb

傳輸大小,90%:1,643.1kb

數據集:使用 Angular 的站點

傳輸大小,10%:468.8kb

傳輸大小,25%:716.9kb

傳輸大小,50%:1,144.2kb

傳輸大小,75%:1,930.0kb

傳輸大小,90%:3,283.1kb

數據集:使用 React 的站點

傳輸大小,10%:308.6kb

傳輸大小,25%:469.0kb

傳輸大小,50%:841.9kb

傳輸大小,75%:1,472.2kb

傳輸大小,90%:2,197.8kb

JQuery、Vue、React、Angular,JavaScript框架成本終極對比 2

站點負載大小數據來看,第 10 個百分點的結果和你想的基本差不多:如果站點使用了這些框架(不管是哪一種),即使在最理想的情況下也會有更多的 JavaScript。這沒什麼好奇怪的——你不能一邊把 JavaScript 框架用作默認起點,另一邊還期望框架能讓網站使用的 JavaScript 代碼變少。

值得注意的是,某些框架比其他對手有著更好的起點。使用 jQuery 的網站表現最佳,其在桌面設備上增加的 JavaScript 約 15%起步,在移動設備上增加的 JavaScript 約 18%起步。 (這裡確實存在一些偏見。在許多站點上都可以找到jQuery,因此自然而然地,它與數據整體的關係要比其他框架更為緊密。但是,這並沒有改變各個框架統計出來的原始數據所展示的情況。)

值得注意的是,儘管 jQuery 帶來了 15-18%的體積增加,但與另一端的數據對比時就會發現 jQuery 稅是非常低的。使用 Angular 的網站在桌面上第 10 個百分點的體積膨脹了 344%,在移動設備上則是 377%。第二笨重的 React 網站在桌面上的 JavaScript 體積比總體值高出 193%,在移動設備上則是 270%。

我在前面提到過,就算框架的起點差一些,我也希望它們可以通過某種方式限制代碼的體積上限來提供價值。

有趣的是,jQuery 驅動的網站就遵循這種模式。儘管它們在第 10 個百分點上的表現稍微偏高(比總體值高出 15-18%),但在第 90 個百分點上的數據就小得多——桌面和移動版均約為 3%。這些數字都沒那麼大,所以至少就 jQuery 發送的 JavaScript 代碼體積而言,數據的長尾部分似乎沒那麼糟糕。

其他框架就不是這麼一回事了

在第 10 個百分點上,Angular 和 React 驅動的站點比其他框架在第 90 個百分點上的體積還大,令人不爽。

在第 90 個百分點上,Angular 站點在移動設備上發送的字節數增加了 141%,在桌面上發送的字節增加了 159%。使用 React 的網站在桌面上的字節數增加了 73%,在移動設備上的字節數增加了 58%。 React 站點在移動設備的第 90 個百分點為 2,197.8kb,比第二差的 Vue.js 多了 322.9kb 的 JavaScript。 Angular 和 React 在桌面上與其他框架的差距更大,與 Vue.js 驅動的網站相比,React 驅動的網站提供的 JavaScript 多了 554.7kb。

JavaScript 主線程時間

從數據中可以明顯看出,採用這些框架的網站在站點體積方面往往會付出巨大的代價。但當然,這只是等式的一部分。

一旦 JavaScript 代碼到達客戶端就必須開始執行。瀏覽器主線程上發生的任何事情都特別麻煩。主線程負責在樣式計算、佈局和繪製期間處理用戶輸入。如果我們用大量的 JavaScript 代碼來阻塞主線程,那麼它就沒有機會及時執行這些操作,從而導致卡頓和混亂。

HTTP Archive 記錄了 V8 主線程的執行時間,因此我們可以查詢這些數據以了解它在所有 JavaScript 代碼上的處理時間。

移動設備上腳本相關的 CPU 時間(以毫秒為單位),按百分點排序

數據集:所有網站

主線程時間,10%:356.4 毫秒

主線程時間,25%:959.7 毫秒

主線程時間,50%:2,372.1 毫秒

主線程時間,75%:5,367.3 毫秒

主線程時間,90%:10,485.8 毫秒

數據集:使用 jQuery 的網站

主線程時間,10%:575.3 毫秒

主線程時間,25%:1,147.4 毫秒

主線程時間,50%:2,555.9 毫秒

主線程時間,75%:5,511.0 毫秒

主線程時間,90%:10,349.4 毫秒

數據集:使用 Vue.js 的網站

主線程時間,10%:1,130.0 毫秒

主線程時間,25%:2,087.9 毫秒

主線程時間,50%:4,100.4 毫秒

主線程時間,75%:7,676.1 毫秒

主線程時間,90%:12,849.4 毫秒

數據集:使用 Angular 的網站

主線程時間,10%:1,471.3 毫秒

主線程時間,25%:2,380.1 毫秒

主線程時間,50%:4,118.6 毫秒

主線程時間,75%:7,450.8 毫秒

主線程時間,90%:13,296.4 毫秒

數據集:使用 React 的網站

主線程時間,10%:2,700.1 毫秒

主線程時間,25%:5,090.3 毫秒

主線程時間,50%:9,287.6 毫秒

主線程時間,75%:14,509.6 毫秒

主線程時間,90%:20,813.3 毫秒

JQuery、Vue、React、Angular,JavaScript框架成本終極對比 3

桌面設備上腳本相關的 CPU 時間(以毫秒為單位),按百分點排序

數據集:所有網站

主線程時間,10%:146.0 毫秒

主線程時間,25%:351.9 毫秒

主線程時間,50%:831.0 毫秒

主線程時間,75%:1,739.8 毫秒

主線程時間,90%:3,236.8 毫秒

數據集:使用 jQuery 的網站

主線程時間,10%:199.6 毫秒

主線程時間,25%:399.2 毫秒

主線程時間,50%:877.5 毫秒

主線程時間,75%:1,779.9 毫秒

主線程時間,90%:3,215.5 毫秒

數據集:使用 Vue.js 的網站

主線程時間,10%:350.4 毫秒

主線程時間,25%:650.8 毫秒

主線程時間,50%:1,280.7 毫秒

主線程時間,75%:2,388.5 毫秒

主線程時間,90%:4,010.8 毫秒

數據集:使用 Angular 的網站

主線程時間,10%:482.2 毫秒

主線程時間,25%:777.9 毫秒

主線程時間,50%:1,365.5 毫秒

主線程時間,75%:2,400.6 毫秒

主線程時間,90%:4,171.8 毫秒

數據集:使用 React 的網站

主線程時間,10%:508.0 毫秒

主線程時間,25%:1,045.6 毫秒

主線程時間,50%:2,121.1 毫秒

主線程時間,75%:4,235.1 毫秒

主線程時間,90%:7,444.3 毫秒

JQuery、Vue、React、Angular,JavaScript框架成本終極對比 4

這裡的結果也和前面有很多相似之處。

首先,檢測到使用了 jQuery 的網站的 JavaScript 花費在主線程上的時間要比其他三種框架少得多。在第 10 個百分點,在移動設備上的 JavaScript 主線程工作量(相比總體數據)增加了 61%,在桌面設備上則增加了 37%。在第 90 個百分點上,jQuery 網站的表現非常接近總體數據,移動設備的主線程時間 減少 了 1.3%,桌面設備的時間 減少 了 0.7%。

另一頭(花費在主線程上的時間最多的框架)又是 Angular 和 React。唯一的區別是,儘管 Angular 站點比 React 站點交付的 JavaScript 代碼體積更大,但實際上前者在 CPU 上花費的時間更少,而且是少很多。

在第 10 個百分點,Angular 網站在桌面設備 CPU 上花費的時間增加了 230%,而在移動設備上則增加了 313%。 React 網站帶來了更多的麻煩,在桌面設備上多出 248%的時間,在移動設備上多出 658%的時間。不,658%不是筆誤。在第 10 個百分點,使用 React 框架的網站需要在主線程上花費足足 2.7 秒才能處理完所有服務器發來的的 JavaScript 代碼。

與這些嚇人的數字相比,第 90 個百分點的情況看起來稍好一些。 Angular 網站的主線程在桌面設備上花費的時間增加了 29%,在移動設備上的時間增加了 27%。 React 網站在桌面上的時間增加了 130%,在移動設備上的時間增加了 98%。

這些百分比看上去比第 10 個百分點要好得多,但是請記住,絕對數值簡直嚇死人了:第 90 個百分點上,在移動設備上使用 React 框架構建的網站的主線程工作時間為 20.8s。 (我認為那段時間發生的事情足以再寫一篇文章了。)

有一個潛在的陷阱(感謝 Jeremy 的建議,讓我從這個角度仔細檢查了統計數據)——許多站點都會引入多個庫。特別是在遷移到新架構時,我看到許多網站都同時使用 jQuery 與 React 或 Vue.js。因此我重新跑了一遍查詢,只是這次查的是只包含 React/jQuery/Angular 或 Vue.js,而不是它們的某種組合的站點。

移動設備上腳本相關的 CPU 時間(以毫秒為單位),只檢測到一個框架,按百分點排序

數據集:只使用 jQuery 的網站

主線程時間,10%:542.o 毫秒

主線程時間,25%:1,062.2 毫秒

主線程時間,50%:2,297.4 毫秒

主線程時間,75%:4,769.7 毫秒

主線程時間,90%:8,718.2 毫秒

數據集:只使用 Vue.js 的網站

主線程時間,10%:944.0 毫秒

主線程時間,25%:1,716.3 毫秒

主線程時間,50%:3,194.7 毫秒

主線程時間,75%:5,959.6 毫秒

主線程時間,90%:9,843.8 毫秒

數據集:只使用 Angular 的網站

主線程時間,10%:1,328.9 毫秒

主線程時間,25%:2,151.9 毫秒

主線程時間,50%:3,695.3 毫秒

主線程時間,75%:6,629.3 毫秒

主線程時間,90%:11,607.7 毫秒

數據集:只使用 React 的網站

主線程時間,10%:2,443.2 毫秒

主線程時間,25%:4,620.5 毫秒

主線程時間,50%:10,061.4 毫秒

主線程時間,75%:17,074.3 毫秒

主線程時間,90%:24,956.3 毫秒

JQuery、Vue、React、Angular,JavaScript框架成本終極對比 5

首先,結果符合預期:當只使用一個框架時,網站的性能(相比多框架並用)往往會明顯提升。每個框架在第 10 個百分點和第 25 個百分點時表現更佳。這就說得通了。用一個框架構建好的網站應該比用兩個或更多框架構建的網站更快一些。

實際上,除了一個奇怪的例外,每個框架在各個百分點上的成績都比上一節更好了。令我感到驚訝的是,只使用 React 框架的網站在第 50 個百分點及以後的表現竟然倒退了,這也是我加入這部分數據的原因。

這個現象就有點奇怪了,下面是我的合理猜想。

如果你同時使用 React 和 jQuery,那麼很可能是因為你正在遷移到 React 或混合代碼庫中。既然我們已經看到,使用 jQuery 的網站在主線程上花費的時間比使用 React 的網站更少,所以可以推理,仍由 jQuery 驅動的某些功能會提升整個站點的速度表現。

但是,當你離開 jQuery 而將更多代碼遷移到 React 上時,情況就會逐漸發生變化了。如果網站建設得非常好,並且你很少使用 React,那倒沒什麼問題。但是對於常見的站點來說,內部更多的代碼跑在 React 上,意味著主線程承受的壓力也隨著遷移進程的推進而越來越大。

移動 / 桌面差距

另一個值得關注的角度是,移動體驗和桌面體驗之間的差距到底有多大。從站點體積的角度來看,兩者之間的差異沒那麼可怕。當然,我希望網站傳輸的數據能盡量少一些,但是移動設備和桌面設備收到的數據量並沒有比對方高出很多。

但一旦轉頭來看處理時間的話,它們的差距就很驚人了。

與桌面設備相比,移動設備上主線程腳本工作時間增加的百分比,按百分點排序

數據集:所有網站

從桌面到移動設備增加的百分比,10%:144.1%

從桌面到移動設備增加的百分比,25%:172.8%

從桌面到移動設備增加的百分比,50%:185.5%

從桌面到移動設備增加的百分比,75%:208.5%

從桌面到移動設備增加的百分比,90%:224.0%

數據集:使用 jQuery 的網站

從桌面到移動設備增加的百分比,10%:188.2%

從桌面到移動設備增加的百分比,25%:187.4%

從桌面到移動設備增加的百分比,50%:191.3%

從桌面到移動設備增加的百分比,75%:209.6%

從桌面到移動設備增加的百分比,90%:221.9%

數據集:使用 Vue.js 的網站

從桌面到移動設備增加的百分比,10%:222.5%

從桌面到移動設備增加的百分比,25%:220.8%

從桌面到移動設備增加的百分比,50%:220.2%

從桌面到移動設備增加的百分比,75%:221.4%

從桌面到移動設備增加的百分比,90%:220.4%

數據集:使用 Angular 的網站

從桌面到移動設備增加的百分比,10%:205.1%

從桌面到移動設備增加的百分比,25%:206.0%

從桌面到移動設備增加的百分比,50%:201.6%

從桌面到移動設備增加的百分比,75%:210.4%

從桌面到移動設備增加的百分比,90%:218.7%

數據集:使用 React 的網站

從桌面到移動設備增加的百分比,10%:431.5%

從桌面到移動設備增加的百分比,25%:386.8%

從桌面到移動設備增加的百分比,50%:337.9%

從桌面到移動設備增加的百分比,75%:242.6%

從桌面到移動設備增加的百分比,90%:179.6%

其實開始研究前我也想到了手機和筆記本電腦之間會有一些速度差異,但結果如此高的數字告訴我,現在這些流行的框架並沒有照顧那些性能較弱的設備,自然也就沒法縮減不同性能水平設備之間的差距。即使在第 10 個百分點上,React 站點在移動設備上的主線程工作時間也要比在台式設備上多出 431.5%。 jQuery 是所有框架中兩個平台差距最小的,但即使是它,在移動設備上的時間也要多出 188.2%。隨著我們給 CPU 帶來愈加沉重的負擔時,那些性能較弱的設備最終會不堪重負。

整體評價

好的框架應該在一些關鍵要素(安全性、可訪問性、性能)上提供一個更好的起點,或者俱有內置的約束條件,讓開發人員更難做出違反這些規則的代碼。

可是在性能要素上這種事情似乎並沒有出現(顯然可訪問性也是一樣)。

值得注意的是,就算使用 React 或 Angular 的網站在 CPU 上花費的時間比其他網站更多,也並不代表 React 的 CPU 開銷比 Vue.js 更高。實際上,上面這些數據與核心框架的實際性能並沒有太大關係,而是更多地反映了在這些框架上開發網站的方法的性能表現,而這些方法是由框架的文檔、生態系統和通行編碼實踐等內容形成的。

還需要注意的是我們這裡沒有提到的內容:設備在查看後續數據時,在這些 JS 代碼上花費的處理時間。 SPA 架構的理念是,一旦 SPA 加載完畢,理論上你將獲得更快的後續頁面加載速度。我自己的經驗告訴我實際情況和理想相差甚遠,但我們這裡沒有具體的數據來驗證。

顯而易見的是:目前,如果你使用某種框架來構建網站,那麼即使在最理想的情況下也要犧牲初始加載的速度。

在適當的情況下可以做一些權衡取捨,但重要的是我們必須有意識地做出這種決策。

當然我們也有理由對未來的發展報以樂觀的心態。 Chrome 團隊正在與其中一些框架緊密合作,以幫助改善後者的性能表現,這讓我感到很欣慰。

但我也是很務實的。新的架構往往會在解決舊的性能問題的同時頻繁地產生新的性能問題,並且糾正問題是要花費時間的。正如我們不應該期望新的高速網絡能解決我們所有的性能問題一樣,我們也不應該期望我們喜歡的框架的下一個版本能夠解決所有這些問題。

如果要使用其中某個框架,開發人員必須採取額外的步驟以確保不會對網站的性能產生負面影響。以下是一些不錯的注意事項參考:

  • 做一個健全性檢查:你真的需要使用它嗎?原版 JavaScript 現在就可以做很多事情。
  • 有沒有更輕巧的替代品(Preact,Svelte 等),可以讓你達成 90% 的目標?
  • 如果你要使用一個框架,是否有東西可以提供更好、更合理的默認項(例如 Nuxt.js 代替 Vue.js,Next.js 代替 React 等)?[注 2]
  • 你的 JavaScript 的性能預算是多少?
  • 你會在工作流程中引入怎樣的約束,避免自己添加那些並非絕對必要的 JavaScript?
  • 如果你要使用的框架是為提升開發效率準備的,那麼是否需要將其交付給客戶端,還是可以在服務器上處理所有工作?

無論你選擇哪種技術,這些都是值得仔細思考的問題;如果你從一開始就遇到了性能缺陷,那麼這些問題尤其需要好好考慮了。

附註

1、我考慮過使用其他基準。

例如,我們可以使用未檢測到上述任何框架(jQuery、React、Vue.js、Angular)的所有站點。

以下是這些網站在移動設備上運行 JavaScript 的主線程耗時:

移動設備上與腳本相關的 CPU 處理時間(以毫秒為單位),按百分點排序

數據集:所有網站

主線程時間,10%:6.3 毫秒

主線程時間,25%:75.3 毫秒

主線程時間,50%:382.2 毫秒

主線程時間,75%:2,316.6 毫秒

主線程時間,90%:5,504.7 毫秒

更進一步,我們可以使用所有未檢測到 JavaScript 框架或庫的網站做基準。這些網站的主線程時間如下所示:

移動設備上與腳本相關的 CPU 處理時間(以毫秒為單位),按百分點排序

數據集:所有網站

主線程時間,10%:3.6 毫秒

主線程時間,25%:29.9 毫秒

主線程時間,50%:193.2 毫秒

主線程時間,75%:1,399.6 毫秒

主線程時間,90%:3,714.5ms

無論採用哪種基線,數據看起來都對框架不太有利,而且差別更明顯了。最後我選擇了聚合數據作為基準,因為:

  • 社區中討論這種話題時基本都會使用它。
  • 它避免了”沒有框架的站點是否足夠複雜,以提供準確的對比”的辯論。你完全可以在不使用框架的前提下構建大型複雜站點(我就和這樣幹的公司合作過),但這個論點會讓人忽視數據中本來非常清晰的結論。

不過,很多人都說上面這些基準很有趣,因為它們展示出了整體水平受到了這些工具的影響到底有多大。

2、我懷疑人們只從框架開始,就可以構建出優於 Next.js 或 Nuxt.js 的東西。不過,這裡的數據長尾表明,對於許多網站而言情況並非如此。建立起這些框架提供的所有管道,並構建表現良好的代碼需要花費很多時間。所以做出引入框架的決策之前,還是應該好好考慮一下自己到底要加入多少抽象層。

英文原文

The Cost of JavaScript Frameworks