前端性能優(yōu)化

我們都知道對于Web應用來說性能很重要危喉。然而性能優(yōu)化相關的知識卻非常的龐大并且雜亂。對于性能優(yōu)化需要做些什么以及性能瓶頸是什么,通常我們并不清楚(不包括那些對性能優(yōu)化有豐富經驗的高手)晋柱。

事實上關于Web性能有很多可以優(yōu)化的點砸讳,其中涉及到的知識大致可以劃分為幾類:度量標準琢融、編碼優(yōu)化靜態(tài)資源優(yōu)化簿寂、交付優(yōu)化漾抬、構建優(yōu)化性能監(jiān)控常遂。

image

編碼優(yōu)化

編碼優(yōu)化涉及到應用的運行時性能纳令,本小節(jié)介紹幾個可以提升程序運行時性能的建議。

2.1 數據讀取速度

事實上數據訪問速度有快慢之分克胳,下面列出幾個影響數據訪問速度的因素:

  • 字面量與局部變量的訪問速度最快平绩,數組元素和對象成員相對較慢

  • 變量從局部作用域到全局作用域的搜索過程越長速度越慢

  • 對象嵌套的越深,讀取速度就越慢

  • 對象在原型鏈中存在的位置越深漠另,找到它的速度就越慢

推薦的做法是緩存對象成員值捏雌。將對象成員值緩存到局部變量中會加快訪問速度

2.2 DOM

應用在運行時,性能的瓶頸主要在于DOM操作的代價非常昂貴笆搓,下面列出一些關于DOM操作相關提升性能的建議:

  • 在JS中對DOM進行訪問的代價非常高性湿。請盡可能減少訪問DOM的次數(建議緩存DOM屬性和元素、把DOM集合的長度緩存到變量中并在迭代中使用砚作。讀變量比讀DOM的速度要快很多窘奏。)

  • 重排與重繪的代價非常昂貴。如果操作需要進行多次重排與重繪葫录,建議先讓元素脫離文檔流着裹,處理完畢后再讓元素回歸文檔流,這樣瀏覽器只會進行兩次重排與重繪(脫離時和回歸時)米同。

  • 善于使用事件委托

2.3 流程控制

下面列出一些流程控制相關的一些可以略微提升性能的細節(jié)骇扇,這些細節(jié)在大型開源項目中大量運用(例如Vue):

  • 避免使用for...in(它能枚舉到原型,所以很慢)

  • 在JS中倒序循環(huán)會略微提升性能

  • 減少迭代的次數

  • 基于循環(huán)的迭代比基于函數的迭代快8倍

  • 用Map表代替大量的if-else和switch會提升性能

3靜態(tài)資源優(yōu)化

Web應用的運行離不開靜態(tài)資源面粮,所以對靜態(tài)資源的優(yōu)化至關重要少孝。

3.1 使用Brotli或Zopfli進行純文本壓縮

在最高級別的壓縮下Brotli會非常慢(但較慢的壓縮最終會得到更高的壓縮率)以至于服務器在等待動態(tài)資源壓縮的時間會抵消掉高壓縮率帶來的好處,但它非常適合靜態(tài)文件壓縮熬苍,因為它的解壓速度很快稍走。

使用Zopfli壓縮可以比Zlib的最大壓縮提升3%至8%袁翁。

3.2 圖片優(yōu)化

盡可能通過srcset,sizes和<picture>元素使用響應式圖片婿脸。還可以通過<picture>元素使用WebP格式的圖像橘原。

響應式圖片可能大家未必聽說過蛔垢,但響應式布局大家肯定都聽說過胁出。響應式圖片與響應式布局類似三娩,它可以在不同屏幕尺寸與分辨率的設備上都能良好工作(比如自動切換圖片大小、自動裁切圖片等)抑钟。

當然涯曲,如果您不滿足這種尺度的優(yōu)化,還可以對圖片進行更深層次的優(yōu)化在塔。例如:模糊圖片中不重要的部分以減小文件大小幻件、使用自動播放與循環(huán)的HTML5視頻替換GIF圖,因為視頻比GIF文件還行乃住(好消息是未來可以通過img標簽加載視頻)傲武。

4交付優(yōu)化

交付優(yōu)化指的是對頁面加載資源以及用戶與網頁之間的交付過程進行優(yōu)化蓉驹。

4.1 異步無阻塞加載JS

JS的加載與執(zhí)行會阻塞頁面渲染城榛,可以將Script標簽放到頁面的最底部。但是更好的做法是異步無阻塞加載JS态兴。有多種無阻塞加載JS的方法:defer狠持、async、動態(tài)創(chuàng)建script標簽瞻润、使用XHR異步請求JS代碼并注入到頁面喘垂。

但更推薦的做法是使用defer或async。如果使用defer或async請將Script標簽放到head標簽中绍撞,以便讓瀏覽器更早地發(fā)現資源并在后臺線程中解析并開始加載JS正勒。

4.2 使用Intersection Observer實現懶加載

懶加載是一個比較常用的性能優(yōu)化手段,下面列出了一些常用的做法:

  • 可以通過Intersection Observer延遲加載圖片傻铣、視頻章贞、廣告腳本、或任何其他資源非洲。

  • 可以先加載低質量或模糊的圖片鸭限,當圖片加載完畢后再使用完整版圖片替換它。

延遲加載所有體積較大的組件两踏、字體败京、JS、視頻或Iframe是一個好主意

4.3 優(yōu)先加載關鍵的CSS

CSS資源的加載對瀏覽器渲染的影響很大梦染,默認情況下瀏覽器只有在完成<head>標簽中CSS的加載與解析之后才會渲染頁面赡麦。如果CSS文件過大,用戶就需要等待很長的時間才能看到渲染結果。針對這種情況可以將首屏渲染必須用到的CSS提取出來內嵌到<head>中泛粹,然后再將剩余部分的CSS用異步的方式加載车荔。可以通過Critical做到這一點戚扳。

4.4 資源提示(Resource Hints)

Resource Hints(資源提示)定義了HTML中的Link元素與dns-prefetch忧便、preconnect、prefetch與prerender之間的關系帽借。它可以幫助瀏覽器決定應該連接到哪些源珠增,以及應該獲取與預處理哪些資源來提升頁面性能。

4.4.1 dns-prefetch

dns-prefetch可以指定一個用于獲取資源所需的源(origin)砍艾,并提示瀏覽器應該盡可能早的解析蒂教。

4.4.2 preconnect

preconnect用于啟動預鏈接,其中包含DNS查找脆荷,TCP握手凝垛,以及可選的TLS協(xié)議,允許瀏覽器減少潛在的建立連接的開銷蜓谋。

4.4.3 prefetch

Prefetch用于標識下一個導航可能需要的資源梦皮。瀏覽器會獲取該資源,一旦將來請求該資源桃焕,瀏覽器可以提供更快的響應剑肯。

瀏覽器不會預處理、不會自動執(zhí)行观堂、不會將其應用于當前上下文让网。

as與crossorigin選項都是可選的。

4.4.4 prerender

prerender用于標識下一個導航可能需要的資源师痕。瀏覽器會獲取并執(zhí)行溃睹,一旦將來請求該資源,瀏覽器可以提供更快的響應胰坟。

瀏覽器將預加載目標頁面相關的資源并執(zhí)行來預處理HTML響應因篇。

4.5 Preload

通過一個現有元素(例如:img,script腕铸,link)聲明資源會將獲取與執(zhí)行耦合在一起惜犀。然而應用可能只是想要先獲取資源,當滿足某些條件時再執(zhí)行資源狠裹。

Preload提供了預獲取資源的能力虽界,可以將獲取資源的行為從資源執(zhí)行中分離出來。因此涛菠,Preload可以構建自定義的資源加載與執(zhí)行莉御。

例如撇吞,應用可以使用Preload進行CSS資源的預加載、并且同時具備:高優(yōu)先級礁叔、不阻塞渲染等特性牍颈。然后應用程序在合適的時間使用CSS資源:

4.6 快速響應的用戶界面

PSI(Perceptual Speed Index,感知速度指數)是提升用戶體驗的重要指標琅关,讓用戶感覺到頁面的反饋比沒有反饋體驗要好很多煮岁。

可以嘗試使用骨架屏或添加一些Loading過渡動畫提示用戶體驗。

輸入響應(Input responsiveness)指標同樣重要涣易,甚至更重要画机。試想,用戶點擊了網頁后缺毫無反應會是什么心情新症。JS的單線程大家已經不能再熟悉步氏,這意味著當JS在運行時用戶界面處于“鎖定”狀態(tài),所以JS同步執(zhí)行的時間越長徒爹,用戶等待響應的時間也就越長荚醒。

據調查,JS執(zhí)行100毫秒以上用戶就會明顯覺得網頁變卡了隆嗅。所以要嚴格限制每個JS任務執(zhí)行時間不能超過100毫秒界阁。

解決方案是可以將一個大任務拆分成多個小任務分布在不同的Macrotask中執(zhí)行(通俗的說是將大的JS任務拆分成多個小任務異步執(zhí)行)¢晃停或者使用WebWorkers铺董,它可以在UI線程外執(zhí)行JS代碼運算,不會阻塞UI線程禀晓,所以不會影響用戶體驗。

應用越復雜坝锰,主動管理UI線程就越重要

5

構建優(yōu)化

現代前端應用都需要有構建的過程粹懒,項目在構建過程中是否進行了合理的優(yōu)化,會對Web應用的性能有著巨大的影響顷级。例如:影響構建后文件的體積凫乖、代碼執(zhí)行效率、文件加載時間弓颈、首次有效繪制指標等帽芽。

5.1 使用預編譯

拿Vue舉例,如果您使用單文件組件開發(fā)項目翔冀,組件會在編譯階段將模板編譯為渲染函數导街。最終代碼被執(zhí)行時可以直接執(zhí)行渲染函數進行渲染。而如果您沒有使用單文件組件預編譯代碼纤子,而是在網頁中引入vue.min.js搬瑰,那么應用在運行時需要先將模板編譯成渲染函數款票,然后再執(zhí)行渲染函數進行渲染。相比預編譯泽论,多了模板編譯的步驟艾少,所以會浪費很多性能。

5.2 使用 Tree-shaking翼悴、Scope hoisting缚够、Code-splitting

Tree-shaking是一種在構建過程中清除無用代碼的技術。使用Tree-shaking可以減少構建后文件的體積鹦赎。

目前Webpack與Rollup都支持Scope Hoisting潮瓶。它們可以檢查import鏈,并盡可能的將散亂的模塊放到一個函數中钙姊,前提是不能造成代碼冗余毯辅。所以只有被引用了一次的模塊才會被合并。使用Scope Hoisting可以讓代碼體積更小并且可以降低代碼在運行時的內存開銷煞额,同時它的運行速度更快思恐。前面2.1節(jié)介紹了變量從局部作用域到全局作用域的搜索過程越長執(zhí)行速度越慢,Scope Hoisting可以減少搜索時間膊毁。

code-splitting是Webpack中最引人注目的特性之一胀莹。此特性能夠把代碼分離到不同的bundle中,然后可以按需加載或并行加載這些文件婚温。code-splitting可以用于獲取更小的bundle描焰,以及控制資源加載優(yōu)先級,如果使用合理栅螟,會極大影響加載時間荆秦。

5.3 服務端渲染(SSR)

單頁應用需要等JS加載完畢后在前端渲染頁面,也就是說在JS加載完畢并開始執(zhí)行渲染操作前的這段時間里瀏覽器會產生白屏力图。

服務端渲染(Server Side Render步绸,簡稱SSR)的意義在于彌補主要內容在前端渲染的成本,減少白屏時間吃媒,提升首次有效繪制的速度瓤介。可以使用服務端渲染來獲得更快的首次有效繪制赘那。

比較推薦的做法是:使用服務端渲染靜態(tài)HTML來獲得更快的首次有效繪制刑桑,一旦JavaScript加載完畢再將頁面接管下來。

5.4 使用import函數動態(tài)導入模塊

使用import函數可以在運行時動態(tài)地加載ES2015模塊募舟,從而實現按需加載的需求祠斧。

這種優(yōu)化在單頁應用中變得尤為重要,在切換路由的時候動態(tài)導入當前路由所需的模塊胃珍,會避免加載冗余的模塊(試想如果在首次加載頁面時一次性把整個站點所需要的所有模塊都同時加載下來會加載多少非必須的JS梁肿,應該盡可能的讓加載的JS更小蜓陌,只在首屏加載需要的JS)。

使用靜態(tài)import導入初始依賴模塊吩蔑。其他情況下使用動態(tài)import按需加載依賴

5.5 使用HTTP緩存頭

正確設置expires钮热,cache-control和其他HTTP緩存頭。

推薦使用Cache-control: immutable避免重新驗證烛芬。

6 其他

其他一些值得考慮的優(yōu)化點:

  • HTTP2

  • 使用最高級的CDN(付費的比免費的強的多)

  • 優(yōu)化字體

  • 其他垂直領域的性能優(yōu)化

7 性能監(jiān)控

最后隧期,你可能需要一個性能檢測工具來持續(xù)監(jiān)視網站的性能。

8總結

最后用一張圖來總結這篇文章所表達的內容赘娄,感謝@anjia幫忙畫的這張圖仆潮。

image
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市遣臼,隨后出現的幾起案子性置,更是在濱河造成了極大的恐慌,老刑警劉巖揍堰,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鹏浅,死亡現場離奇詭異,居然都是意外死亡屏歹,警方通過查閱死者的電腦和手機隐砸,發(fā)現死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蝙眶,“玉大人季希,你說我怎么就攤上這事∮姆祝” “怎么了式塌?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長霹崎。 經常有香客問我珊搀,道長,這世上最難降的妖魔是什么尾菇? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮囚枪,結果婚禮上派诬,老公的妹妹穿的比我還像新娘。我一直安慰自己链沼,他們只是感情好默赂,可當我...
    茶點故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著括勺,像睡著了一般缆八。 火紅的嫁衣襯著肌膚如雪曲掰。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天奈辰,我揣著相機與錄音栏妖,去河邊找鬼。 笑死奖恰,一個胖子當著我的面吹牛吊趾,可吹牛的內容都是我干的。 我是一名探鬼主播瑟啃,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼论泛,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蛹屿?” 一聲冷哼從身側響起屁奏,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎错负,沒想到半個月后坟瓢,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡湿颅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年载绿,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片油航。...
    茶點故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡崭庸,死狀恐怖,靈堂內的尸體忽然破棺而出谊囚,到底是詐尸還是另有隱情怕享,我是刑警寧澤,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布镰踏,位于F島的核電站函筋,受9級特大地震影響,放射性物質發(fā)生泄漏奠伪。R本人自食惡果不足惜跌帐,卻給世界環(huán)境...
    茶點故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望绊率。 院中可真熱鬧谨敛,春花似錦、人聲如沸滤否。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽藐俺。三九已至炊甲,卻和暖如春泥彤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背卿啡。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工吟吝, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人牵囤。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓爸黄,卻偏偏與公主長得像,于是被迫代替她去往敵國和親揭鳞。 傳聞我的和親對象是個殘疾皇子炕贵,可洞房花燭夜當晚...
    茶點故事閱讀 45,685評論 2 360

推薦閱讀更多精彩內容

  • 圍繞前端的性能多如牛毛,涉及到方方面面野崇,以我我們將圍繞PC瀏覽器和移動端瀏覽器的優(yōu)化策略進行羅列注意称开,是羅列不是展...
    流動碼文閱讀 679評論 0 0
  • 隨著前端頁面的復雜化,網頁的載入速度是越來越慢了乓梨,而最近的日子里面鳖轰,Google 等公司也是在大力推動 PWA 的...
    azzgo閱讀 872評論 0 2
  • 在這個前端用戶體驗越來越重要的時代,你的頁面稍微有點卡頓蕴侣,都難以挽留用戶臭觉。而作為一名有追求的前端狞膘,勢必要力所能及地...
    SCQ000閱讀 3,835評論 0 52
  • 【打卡始于2017.10.14持續(xù)于2017.12.25-31】 今天晚上是跨年夜臣镣,就是元旦了忆某,祝福我生命中遇到的...
    lovelyfener閱讀 123評論 1 1
  • 今天上午上完課馍忽,下午就是空閑的,中午出去取了蛋糕徒探,又去吃飯,很瘋狂的下午碗啄,很多照片,桌上一片狼藉胆描,臉上一片...
    梨花開一樹閱讀 215評論 0 1