摘要:目前我們的業(yè)務(wù)項(xiàng)目采用的來進(jìn)行優(yōu)化和首屏性能提升。可變性需要讓開發(fā)人員降低開發(fā)時(shí)的基準(zhǔn)線,來保證每一個(gè)用戶的體驗(yàn)。對(duì)于路由的切分以及庫的引入來說,這一個(gè)原則至關(guān)重要。快速生成一份站點(diǎn)的性能審查報(bào)告。
The Cost Of JavaScript 2018 關(guān)于原文
原文是在Medium上面看到的,Chrome工程師Addy Osmani發(fā)布的一篇文章,這位的Medium上面的自我介紹里面有一句Passionate about making the web fast,和這篇文章的主體可以說非常契合了。
最近在做一個(gè)服務(wù)端渲染的項(xiàng)目,到底頁面性能的提升能夠帶來多少的意義,或者到底有多少合理的方法來讓精雕細(xì)琢移動(dòng)端的用戶體驗(yàn)。
這篇文章主要是部分內(nèi)容的翻譯,并且結(jié)合自己的一些想法,以備在項(xiàng)目架構(gòu)的時(shí)候考慮到這些相關(guān)的東西。
原文內(nèi)容會(huì)按照引用樣式排版
原文-The Cost Of JavaScript 2018
前言首先,JavaScript仍舊是我們發(fā)送到用戶移動(dòng)設(shè)備上的最昂貴的資源,因?yàn)樗梢栽诤艽蟪潭壬涎舆t用戶的交互。
JavaScript阻塞頁面上的交互動(dòng)作,所有同步執(zhí)行的JavaScript代碼不會(huì)中斷自己的執(zhí)行來給突然觸發(fā)的交互事件讓路,并且如果在交互的時(shí)候需要頁面樣式的變化,也是會(huì)被阻塞的。React 16中新加入的Fiber功能,就是為了將同步的re-render操作分片,來讓頁面的交互可以間歇進(jìn)行而不是完全阻塞。關(guān)于React Fiber的原理,可以看這一篇:React 16.0 Fiber源碼解讀。
React在Release Note中也寫到了,React 16還有一大進(jìn)步就是相比起15.6版本來說,其react庫壓縮到了5.3kb,gzip壓縮后可以達(dá)到2.2kb,而react-dom庫也從141kb壓縮到了103.7kb,庫大小的減少也能夠很好地提升React在客戶端的執(zhí)行速度,在頁面首次渲染的時(shí)候加載更少的資源。
為了保證速度,僅僅加載當(dāng)前頁面必須的JavaScript;
提前做好性能預(yù)算,并且合理利用;
做好JavaScript打包以及代碼審計(jì)工作;
每一個(gè)交互都是從一個(gè)新的“可交互時(shí)間”開始的,考慮如何在這種情況下進(jìn)行優(yōu)化;
如果一段客戶端JavaScript并不能夠提升用戶體驗(yàn),那么就要問問你自己這段代碼是否是必須的。
原文的文章很長,所以放了一個(gè)tl;dr:在文章最前面,文章的五個(gè)重點(diǎn)都列出來了,如何壓榨每一個(gè)Byte的JavaScript的性能,需要從多個(gè)方面考慮可精簡的JavaScript。
web由于用戶“體驗(yàn)”而膨脹也許你根本就不知道自己頁面中的JavaScript到底占據(jù)了多少物理資源來執(zhí)行,尤其是在移動(dòng)設(shè)備上。目前的現(xiàn)代網(wǎng)頁平均會(huì)使用250KB的壓縮JavaScript,如果沒有壓縮的話,大概是1MB左右的腳本,這些腳本都需要瀏覽器來執(zhí)行,無論是在移動(dòng)設(shè)備還是PC上面。
在公司網(wǎng)絡(luò)的環(huán)境下,使用lighthouse來對(duì)網(wǎng)易云音樂的首頁進(jìn)行檢測(cè),從開始HTTP請(qǐng)求一直到頁面開始可以交互的時(shí)間大概在3s左右,根據(jù)5s原則來說,已經(jīng)是一個(gè)很好的體驗(yàn)了,很多元素的延遲加載起到了很好的作用。如果你想看到自己的網(wǎng)頁性能到底如何,可以使用lighthouse快速生成一個(gè)網(wǎng)頁性能的檢測(cè)報(bào)告。
移動(dòng)端用戶體驗(yàn)隨著JavaScript阻塞交互事件超過14秒以上,逐漸消失。
導(dǎo)致移動(dòng)端上面代碼阻塞時(shí)間的主要原因是移動(dòng)端CPU的性能以及網(wǎng)絡(luò)狀況。
這里顯示的中國并不是4G覆蓋率非常低,而是沒有數(shù)據(jù),但是可以看到西歐、北美等地區(qū)的4G覆蓋率也只是60%~80%之間,并不能夠達(dá)到基本全覆蓋,所以為了這部分3G用戶的用戶體驗(yàn),縮減JavaScript壓縮后文件的大小也是必然的。
并且移動(dòng)端設(shè)備的性能也是瓶頸之一,智能手機(jī)的普及率雖然比較高,但是質(zhì)量參差不齊,許多移動(dòng)端設(shè)備還停留在1G甚至512RAM的情況下。
大部分互聯(lián)網(wǎng)公司都會(huì)采用兩套web來實(shí)現(xiàn)移動(dòng)端和桌面端,移動(dòng)端采用高壓縮的頁面,來減少網(wǎng)絡(luò)時(shí)間和加載時(shí)間。
JavaScript存在成本如果頁面有著過多的腳本,那么就需要考慮code-spliting來分開bundle代碼,或者通過tree-shaking來減少JavaScript的包袱。
目前我們的業(yè)務(wù)項(xiàng)目采用React+Node.js的SSR來進(jìn)行SEO優(yōu)化和首屏性能提升。我們的JS Bundle中有著很多的JavaScript庫代碼:
react&& react-dom等客戶端框架;
大型SPA可選的狀態(tài)管理解決方案:mobx、vuex、redux、rxjs;
ES6、ES7等polyfills,為瀏覽器廠商還債;
@music等組件庫,包括Utils組件以及UI組件。
即使已經(jīng)完成了code split,首屏加載中,上面的這些庫也會(huì)有一大部分被加載進(jìn)來,造成整個(gè)項(xiàng)目的JavaScript冗余。
整個(gè)頁面在加載的時(shí)候,有著幾個(gè)重要的時(shí)間節(jié)點(diǎn)。
是否開始有內(nèi)容顯示在頁面上了。也就是用戶能夠感受到自己得到了響應(yīng);是否有完整的內(nèi)容顯示在頁面上,也就是可交互的內(nèi)容已經(jīng)顯示了出來;
是否可以開始進(jìn)行交互了,也就是意味著用戶能夠開始對(duì)頁面進(jìn)行正常操作。
前兩個(gè)階段在服務(wù)端渲染的情況下,大部分進(jìn)行的還是頁面的render操作,render是沒有太多辦法來對(duì)其進(jìn)行加速的。所以為了提升交互效果,第三階段是必須著力解決的。不能夠產(chǎn)生交互的主要原因是腳本還沒有加載完成,導(dǎo)致了頁面阻塞。加速加載和執(zhí)行,通過減少JavaScript包的大小是可行的方法。
另外一種方法是通過SSR,為用戶提供更快的首屏渲染速度,并且在之后,將JavaScript注入到頁面當(dāng)中。
通過標(biāo)簽等主進(jìn)程加載過多的JavaScript會(huì)造成阻塞問題,而采用Web Worker進(jìn)程或者緩存來進(jìn)行頁面腳本的執(zhí)行能夠得到更短的阻塞時(shí)間。
我們估測(cè)了Google News的移動(dòng)端可交互時(shí)間,在高端設(shè)備上大約是7秒左右,而低端設(shè)備則達(dá)到了55秒。
中低端設(shè)備的JavaScript運(yùn)行速度遠(yuǎn)遠(yuǎn)比我預(yù)期的要長很多,由于生活和工作環(huán)境中較少接觸這類設(shè)備,所以這類用戶設(shè)備的比例是需要進(jìn)行埋點(diǎn)獲取的,如果這類設(shè)備的比例較高(在國內(nèi)是比較有可能發(fā)生的),那么就需要為這類用戶進(jìn)行JavaScript的削減或者壓縮。
Pinterest將打包后的JavaScript從2.5MB壓縮到了小于200KB,響應(yīng)時(shí)間從23秒降低到了5.6秒,這樣帶來的直接結(jié)果就是,他們的收入提升了44%而注冊(cè)量提升了753%Orz,移動(dòng)端的周活提升了103%。
我們需要做的重點(diǎn)是防止JavaScript成為整個(gè)網(wǎng)站的瓶頸。
需要記住的是,如果想要讓JavaScript變得更快,那么需要做到下面幾點(diǎn):
下載快
解析快
編譯快
執(zhí)行快
Parse/Compile上面是各大網(wǎng)站在V8引擎上面的腳本執(zhí)行時(shí)間圖,解析和編譯階段占了總時(shí)間的大約10%~30%,在Chrome 66中,V8可以在后臺(tái)線程編譯代碼,可以將編譯時(shí)間減低到大約20%左右,但是也很少見到能夠在50ms之內(nèi)編譯完的JavaScript代碼。
另一個(gè)要注意的事情就是,JavaScript的大小并不完全意味著它的時(shí)間消耗,一個(gè)200KB的圖片和一個(gè)200KB的JavaScript所占用的時(shí)間是完全不同的。
兩者的下載時(shí)間應(yīng)該是差不多并且和大小強(qiáng)相關(guān)的,但是圖片需要解碼,柵格化以及繪制到屏幕上,而JavaScript代碼包需要解析,編譯以及執(zhí)行。JavaScript的時(shí)間消耗基本是要大于圖片的,這個(gè)差距也取決于設(shè)備的CPU性能。
根據(jù)上述內(nèi)容,在進(jìn)行性能測(cè)試的時(shí)候,盡量讓環(huán)境惡劣起來,不要使用高速的網(wǎng)絡(luò)環(huán)境以及高性能設(shè)備來進(jìn)行測(cè)試。因?yàn)橛脩粼O(shè)備和環(huán)境的均值可能是你想象不到的。
可變性會(huì)殺死用戶體驗(yàn),高性能設(shè)備可能會(huì)變慢,高速網(wǎng)絡(luò)也可能會(huì)變慢,可變性最終會(huì)讓所有事情都變慢。
可變性需要讓開發(fā)人員降低開發(fā)時(shí)的基準(zhǔn)線,來保證每一個(gè)用戶的體驗(yàn)。如果你的團(tuán)隊(duì)能夠通過一些策略來獲知所有訪問你的站點(diǎn)的用戶環(huán)境,那么可以很方便地對(duì)于站點(diǎn)的性能兼容性進(jìn)行測(cè)試。在測(cè)試的時(shí)候,采用用戶中具有代表性的網(wǎng)絡(luò)和設(shè)備環(huán)境來進(jìn)行測(cè)試。
It"s important to know your audience.
對(duì)于網(wǎng)絡(luò),低端網(wǎng)絡(luò)環(huán)境需要更小的JavaScript bundle。這就要求減少代碼的冗余、縮小代碼體積、并且進(jìn)行壓縮;
對(duì)于設(shè)備,做好對(duì)于重復(fù)訪問數(shù)據(jù)的緩存工作,解析時(shí)間對(duì)于低端設(shè)備來說是最重要的。
當(dāng)我們的站點(diǎn)越來越依賴于JavaScript的時(shí)候,我們有時(shí)候就會(huì)為了不容易看見的發(fā)送到客戶端的代碼付出代價(jià)。
如何發(fā)送更少的JavaScript這一點(diǎn)的關(guān)鍵在于如何發(fā)送最少限度的JavaScript到客戶端,并且能夠保證用戶的正常體驗(yàn)。Code-splitting是其中的重點(diǎn)。
目前來說,Code-splitting常用的方法就是在bundle代碼的時(shí)候,僅僅返回當(dāng)前路由對(duì)應(yīng)的相關(guān)代碼,而不返回整個(gè)龐大的代碼包。對(duì)于路由的切分以及庫的引入來說,這一個(gè)原則至關(guān)重要。無論什么理由,都盡量不要將其他路由的代碼注入到當(dāng)前訪問的路由當(dāng)中。路由的懶加載是decrease你的JavaScript加載速度的重點(diǎn)。
import Loadable from "react-loadable"; const LoadableOtherComponent = Loadable({ loader: () => import("./OtherComponent"), loading: () =>Loading...}); const MyComponent = () => {};
在React中添加code-splitting可以通過React Loadable進(jìn)行,這個(gè)庫是一個(gè)HOC,可以動(dòng)態(tài)加載需要的React組件,而不會(huì)在首次渲染的時(shí)候就將所有的頁面組件都加載進(jìn)來,即使它暫時(shí)不會(huì)被使用。
現(xiàn)在也有很多庫可以幫助你來定位自己的代碼包,來幫助你從代碼層面減少JavaScript代碼的長度。比如webpack bundle analyzer,source map explorer,bundle buddy。這些工具會(huì)審視你的代碼,并且找到其中的冗余,大型庫以及一些未使用的依賴。
打包審查可以著重于一些大型依賴,或者是給你一個(gè)較輕的低位替代。措施,優(yōu)化,監(jiān)控以及重復(fù)
如果你不確定自己的工程代碼是否存在這些問題,通過LightHouse可以審查你的站點(diǎn)。
cnpm install -g lighthouse lighthouse http://yoursites.com
快速生成一份站點(diǎn)的性能審查報(bào)告。
云音樂主站的審查報(bào)告大概是這樣的,我們的移動(dòng)端主站大概需要3秒左右的時(shí)間能夠得到交互響應(yīng)。
Code Coverage是一個(gè)用來發(fā)現(xiàn)你的頁面中的未使用JavaScript以及CSS的DevTools。使用這個(gè)工具可以看到頁面中有多少代碼影響了加載性能,并且這些代碼讓你付出多少時(shí)間的代價(jià)。
這是主站測(cè)試環(huán)境下的代碼覆蓋率,可以發(fā)現(xiàn)libs文件基本上有一半都未在使用。而CSS更加夸張,95%的代碼都沒有使用過。
PRPL原則PRPL(Push、Render、Precache、Lazy-Load)模式適用于盡力將每一個(gè)多帶帶路由的代碼拆開,然后利用service worker來pre-cacheJavaScript代碼,這些懶加載的代碼是與當(dāng)前路由強(qiáng)相關(guān)的路由的邏輯代碼。
也就是說,我們?cè)谶M(jìn)行路由加載的時(shí)候,僅僅加載一個(gè)純凈的路由頁面。當(dāng)這個(gè)路由頁面渲染完畢之后,我們通過一個(gè)路由相關(guān)的list來將其他與當(dāng)前路由有跳轉(zhuǎn)規(guī)則的路由頁面加載進(jìn)來,通過service worker來在后臺(tái)線程進(jìn)行懶加載與解析。并且根據(jù)我們當(dāng)前的環(huán)境,來進(jìn)行優(yōu)雅降級(jí),如果設(shè)備不支持后臺(tái)線程,那么就采用主線程來進(jìn)行加載。
性能預(yù)算性能預(yù)算是保證所有開發(fā)人員在一個(gè)頻道的關(guān)鍵,性能預(yù)算定義了一個(gè)常量,來讓團(tuán)隊(duì)有著共同的性能目標(biāo)。
性能預(yù)算一般包括下面幾個(gè)部分:
Milestone timings(里程碑時(shí)間?):這個(gè)時(shí)間一般基于加載頁面時(shí)候的用戶體驗(yàn),比如可以開始交互的時(shí)候。這個(gè)時(shí)間一般是頁面完成加載的精確時(shí)間。
Quality-based metrics:基于純粹的值,比如JavaScript的大小,HTTP請(qǐng)求的數(shù)量,這個(gè)值主要關(guān)注瀏覽器體驗(yàn)。
Rule-based metrics:通過LightHouse或者其他頁面測(cè)試工具得到的評(píng)分。
由于現(xiàn)在的大型項(xiàng)目總都是由多個(gè)開發(fā)人員一起進(jìn)行開發(fā)的,這些開發(fā)人員對(duì)于頁面的性能并沒有一個(gè)統(tǒng)一的標(biāo)準(zhǔn),通過上面三個(gè)標(biāo)準(zhǔn),每個(gè)人在加入了自己的代碼之后就可以對(duì)于性能進(jìn)行測(cè)試,來確認(rèn)自己是否影響到了整個(gè)項(xiàng)目的性能預(yù)算。比如自己的庫導(dǎo)致了團(tuán)隊(duì)的JavaScript代碼超量。這時(shí),團(tuán)隊(duì)的人就需要根據(jù)情況來削減自己的代碼量。
下面的有點(diǎn)可怕,就放原文了:
Here’s an action plan for performance:Create your performance vision. This is a one-page agreement on what business stakeholders and developers consider “good performance”
Set your performance budgets. Extract key performance indicators (KPIs) from the vision and set realistic, measurable targets from them. e.g. “Load and get interactive in 5s”. Size budgets can fall out of this. e.g “Keep JS < 170KB minified/compressed”
?Create regular reports on KPIs.?This can be a regular report sent out to the business highlighting progress and success.
在GIT合并的時(shí)候設(shè)置LightHouse的檢測(cè)規(guī)則,如果導(dǎo)致了LightHouse評(píng)分降低,則blocked該次合并。在對(duì)于性能極致要求的業(yè)務(wù)情況下,這個(gè)方法的確能夠有效地提升業(yè)務(wù)代碼的質(zhì)量。
性能不是一蹴而就的,許多細(xì)小的變動(dòng)都可能會(huì)帶來大的收益。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/108493.html
摘要:舉例來說即便某個(gè)失敗了,也不會(huì)導(dǎo)致的發(fā)生,這樣在不在乎是否有項(xiàng)目失敗,只要拿到都結(jié)束的信號(hào)的場(chǎng)景很有用。對(duì)于則稍有不同只要有子項(xiàng),就會(huì)完成,哪怕第一個(gè)了,而第二個(gè)了,也會(huì),而對(duì)于,這種場(chǎng)景會(huì)直接。 1. 引言 本周精讀的內(nèi)容是:Google I/O 19。 2019 年 Google I/O 介紹了一些激動(dòng)人心的 JS 新特性,這些特性有些已經(jīng)被主流瀏覽器實(shí)現(xiàn),并支持 polyfill...
摘要:雖然正則中可以匹配任何字符,但卻無法匹配換行符。精讀文中列舉的四個(gè)新特性是加入到正則中的。討論地址是精讀正則如果你想?yún)⑴c討論,請(qǐng)點(diǎn)擊這里,每周都有新的主題,周末或周一發(fā)布。 1. 引言 本周精讀的文章是 regexp-features-regular-expressions。 這篇文章介紹了 ES2018 正則支持的幾個(gè)重要特性: Lookbehind assertions - 后行...
摘要:下面我們從前端基礎(chǔ)和底層原理開始講起。對(duì)于和這三個(gè)對(duì)應(yīng)于矢量圖位圖和圖的渲染來說,給前端開發(fā)帶來了重武器,很多小游戲也因此蓬勃發(fā)展。這篇文章受眾之大,后來被人重新整理并發(fā)布為,其中還包括中文版。 showImg(https://segmentfault.com/img/bVbjM5r?w=1142&h=640); 想閱讀更多優(yōu)質(zhì)文章請(qǐng)猛戳GitHub博客,一年百來篇優(yōu)質(zhì)文章等著你! 這...
摘要:高級(jí)開發(fā)人員可能會(huì)仔細(xì)分析他們的捆綁包,以幫助確定減少不必要依賴。在運(yùn)行過程中,長時(shí)間運(yùn)行的可以阻塞主線程導(dǎo)致頁面沒有響應(yīng)。然后當(dāng)最終被取出時(shí),附加事件請(qǐng)注意這有內(nèi)在的花銷。發(fā)送一個(gè)最小功能的頁面包含實(shí)行當(dāng)前功能的。保持低這些問題。 原文 當(dāng)我們構(gòu)建的網(wǎng)頁大量依賴于Javascript,我們有些時(shí)候需要研究那些不太容易看得見的消耗。在這篇文章中,我將介紹為什么一點(diǎn)規(guī)則可以幫助如果你想讓...
閱讀 3778·2021-09-02 09:53
閱讀 2755·2021-07-30 14:57
閱讀 3499·2019-08-30 13:09
閱讀 1202·2019-08-29 13:25
閱讀 815·2019-08-29 12:28
閱讀 1461·2019-08-29 12:26
閱讀 1136·2019-08-28 17:58
閱讀 3310·2019-08-26 13:28