[譯] Javascript開銷(Cost)

旭霸發表於2018-02-18

原文連結:https://medium.com/dev-channel/the-cost-of-javascript-84009f51e99e

當我們建立的網站越來越多依賴Javascript時,我們有時候會為了一些我們不容易看到的地方付出代價。在這邊文章中,我會講述一些規範,如果你想讓你的網站在移動裝置上更快載入和響應的話,這些規範可能會對你有幫助。

tl;dr: less code = less parse/compile + less transfer + less to decompress

tl;dr是too long; don't read的縮寫

網路

當大多數開發者想到Javascript的開銷時,可能會聯想到下載和執行開銷。傳送的資料量越大,那使用者連線的速度就越緩慢。

1_U00XcnhqoczTuJ8NH8UhOw.png

即使在一些大國家,如果使用者的有效網路不是3G, 4G 或者WiFi的話(使用者可能在咖啡廳用著wifi,但是實際網速是2G),那麼這就會成為一個問題。

你可以通過以下幾種方式來減少網路傳輸的開銷:

1_8Spf9To8dzTG3Xy9s57oVA.png

解析/編譯

一旦指令碼下載完成了之後,JS最大的開銷之一就是JS引擎的解析/編譯程式碼。在Chrome開發者工具裡的“效能”模組,解析和編譯程式碼用黃色標識.

1__4gNDmBlXxOF2-KmsOrKkw.png

通過Bottom-Up/Call Tree(呼叫樹),可以看實際的解析/編譯用時:

1_GdrVt_BTTzzBOIoyZZsQZQ.png

但是,為什麼這個很重要呢?

1_Dirw7RdQj9Dktc-Ny6-xbA.png

花費大量時間在解析/編譯程式碼上會延遲使用者與網站的互動,破壞使用者體驗。在網站呈現之前,JS量越大,花在解析/編譯上的時間就越長。

1_6Y665hpxfWNMu2EXu3VGlw.png

對於大小相同的JS和圖片或者網頁字型,JS需要瀏覽器花費的時間最多— Tom Dale

與Javascript相比,處理相同大小的圖片所需要的開銷明顯小很多。

1_PRVzNizF9jQ_QADF5lQHpA.png

當我們討論解析和編譯的速度之慢時,上下文是很重要的。我們的討論是基於平均水平的移動裝置。平均水平的使用者使用的移動裝置可能是CPU/GPU很慢的、沒有L2/L3快取的或者甚至記憶體很有限的。

網路和裝置不總是匹配的。一個使用者可能有很好的網路條件,但是隻有一部爛手機。相反,一個使用者可能有一部神機,卻碰上了龜速網路 — Kristofer Baxter, LinkedIn

JavaScript Start-up Performance文中, 我提到了分別在低端和高階機型中1MB原始JS程式碼的解析時間. 它們之間的差距達到了2-5倍.

1_8BQ3bCYu1AVvJWPR1x8Yig.png

那實際的網站如何呢,比如CNN.com?

在高階機iPhone 8上,解析/編譯JS程式碼只需大約4s,而在平均水平的手機Moto G4上卻要花上將近13s。這很明顯得影響了使用者能夠多快看到介面。

1_7ysArXJ4nN0rQEMT9yZ_Sg.png

這就要求我們要更加註重一些平均水平的裝置的測試,而不僅僅是自己口袋裡的高階機。上下文是很重要的:一定要針對你的使用者的裝置和網路進行優化。

1_6oEpMEi_pjRNjmtN9i2TCA.png

可以通過 mobile device classes 來看看真實使用者的分析情況。

我們真的是傳輸了太多的JS程式碼嗎? 呃。。有可能 :)

使用HTTP Archive (top ~500K sites)來分析JS在移動裝置上的使用情況JavaScript on mobile, 我們就能發現50%左右的網站需要14s以上才能真正讓使用者用上。這些網站光花在解析/編譯JS上的時間就多達4s.

1_sVgunAoet0i5FWEI9NSyMg.png

介於以上這些情況,怪不得使用者在還沒有看到頁面之前就離開了。我們當然可以在這點上做得更好。

刪除一些非必要JS程式碼能有效減少轉換時間、CPU的解析/編譯時間以及記憶體佔用。同樣也能是使用者更快得與網站互動。

執行時間

當然,編譯和解析只是JS開銷的一部分。執行JS程式碼也是主執行緒上必須要做的,如果執行時間冗長,也會直接影響使用者體驗。

1_ec0wEKKVl7iQidBks3oDKg.png

一旦指令碼執行時間超過50ms,後果不堪設想 — Alex Russell

為了減少執行時間,你可以將JS程式碼分離成一塊塊的,以免阻塞主執行緒。

設計模式

有時候一些設計模式能夠幫助你,比如基於路由的程式碼分塊 (route-based chunking) 或者PRPL.

如下圖所示,PRPL就是一個利用程式碼分離和快取方式來優化互動體驗的模式:

1_VgdNbnl08gcetpqE1t9P9w.png

讓我們來看看這個影響.

我們使用V8的 Runtime Call Stats 分析了一些主流網站以及PWA的載入時間。可以看到,解析時間在整個載入時間中佔了可觀的部分:

1_9BMRW5i_bS4By_JSESXX8A.png

Wego,是使用了PRPL的一個站點,讓每個路由都保持很少的解析時間,使得使用者能更快得與網站互動。上圖中的很多網站也是採用了程式碼分離和效能預算 (performance budget) 來嘗試降低JS開銷。

其它開銷

JS也會在其它方面影響頁面效能:

  • 記憶體。頁面可能會因為垃圾回收而導致頻繁的閃爍或暫停。當瀏覽器回收記憶體的時候,JS執行就會暫停。這就導致了當瀏覽器頻繁回收垃圾時,JS執行的暫停頻率就會比我們想象中的更多。避免記憶體洩漏和頻繁的垃圾回收能夠是頁面更穩定。

  • 在執行時,如果JS執行時間過長就會阻塞主程式,導致頁面無法互動。把這些任務分成一小塊一小塊 (可以採用 requestAnimationFrame() 或者 requestIdleCallback() 或者 scheduling) 能夠最小化其帶來的影響。

漸進式 Bootstrapping

為了讓網站更快呈現在使用者面前,許多網站會使用伺服器端渲染來實現,然後在頁面返回後通過繫結事件來“升級”它。

當心 -- 這種方式也有它的開銷。一方面傳輸回來的HTML比較大,另一方面使用者必須等到JS處理完畢才能真正與頁面進行互動。

漸進式 Bootstrapping 可能是一種更好的方法。先傳送一部分功能性頁面(只是當前路由需要的HTML/JS/CSS)回來。當更多的資源傳輸回來時,頁面就會進行懶載入並且解鎖更多的功能。

1_zY03Y5nVEY21FXA63Qe8PA.png

載入當前頁面的程式碼實在是非常好的方法。PRPL和漸進式 Bootstrapping 就是能幫助實現這點的模式。

結論

在網路不佳的情況下,傳輸資料的大小是至關重要的。對於CPU不給力的裝置,解析時間是很重要的。

參考 Alex Russell 的 “Can You Afford It?: Real-world Web Performance Budgets”。

1_U8PJVNrA_tYADQ6_S4HUYw.png

如果你正在搭建一個基於移動裝置的站點,儘量在典型的裝置上開發。減少JS解析/編譯時間,採用Performance Budget讓團隊成員都能檢測JS開銷。

硬廣

這是本人的前端技術小程式,基本上所有的文章都會同步更新在小程式中。歡迎大家來湊熱鬧。

image
image

相關文章