<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          分享一些前端優(yōu)化的小技巧

          共 303字,需瀏覽 1分鐘

           ·

          2021-12-10 02:25

          ?
          會優(yōu)化,我就不是不優(yōu),就是看著慢,哎~,就是玩兒~。

          前言

          性能優(yōu)化是一個項目發(fā)展到一定時期之后繞不開的話題,也是每個工程師心中永遠(yuǎn)在撩撥的刺。

          總結(jié)一下常用的前端性能優(yōu)化的方法,希望對大家有些幫助~。

          性能可能帶來的影響(販賣焦慮警告??)

          試想當(dāng)你做的酷炫特效因為慢了0.1秒就少被一個人看到時的落寞(ㄒoㄒ),

          試想當(dāng)你引以為傲的細(xì)節(jié)交互因為慢了0.2秒就被競爭對手的平庸互動拉走用戶的氣憤(╯>д<)╯?˙3˙?,

          試想當(dāng)你精心打造的漂亮頁面因為慢了0.3秒就被搜索引擎無情的排在后面的無奈∑(O_O;)。

          所以,是時候重拳出擊了,重鑄性能的榮光,我輩義不容辭( ̄▽ ̄)/。

          調(diào)試工具

          Network面板

          Network面板記錄了與服務(wù)器交互的具體細(xì)節(jié)。

          在這里我們可以看到發(fā)起的請求數(shù)量,傳輸體積以及解壓縮后的體積,同時還可以知道哪些資源是命中了強(qiáng)緩存,哪些資源命中的協(xié)商緩存。

          network2.jpg

          查看某一個請求的瀑布流可以讓我們清晰的看到一個資源從服務(wù)器到達(dá)我們的電腦所花的時間。

          如上圖,排隊用了1.65ms,DNS查詢用了21.47ms,initial connection(進(jìn)行TCP握手的時間)用了56.25ms,SSL握手的時間用了37.87ms,然后又用了100多ms第一個字節(jié)到達(dá)我們的電腦(TTFB - 上面的查詢/建立),接收整個文檔花了17ms。

          這時候我們基于上面的信息就可以粗略的得到,如果能在請求資源之前如果已經(jīng)得到DNS地址(預(yù)查詢)可以省去21ms,已經(jīng)進(jìn)行過握手可以省去100ms(預(yù)連接),如果干脆請求也不請求可以省去200ms(緩存)繼而針對這些點做對應(yīng)的策略。

          Network面板可以讓我們初步評估網(wǎng)站性能,對網(wǎng)站整體的體積,網(wǎng)絡(luò)的影響帶來一個整體的認(rèn)知,同時提供一些輔助功能,如禁用緩存,block某些資源。

          lighthouse面板

          lighthouse1.jpg

          lighthouse是對網(wǎng)站整體的評估,通過幾個不同的指標(biāo)給網(wǎng)站進(jìn)行打分。

          First Contentful Paint?首屏渲染時間,Chrome會取第一個渲染出來的元素作為時間參考。

          Time to Interactive?可交互時間,從能看到能摸的時間點。

          Speed Index?速度指數(shù),頁面的填充速度。

          Total Blocking Time?從能看到能摸之間超過50ms的任務(wù)總和。

          Largest Contentful Paint?頁面中最大的那塊渲染的時間點。

          Cumulative Layout Shift?元素移動所累積的時間點,比如有一個absolute的元素突然從左邊移到了右邊。

          同時針對網(wǎng)站的信息,lighthouse還會給出一些完善建議:

          lighthouse2.jpg

          這些建議可以幫助我們在接下來的優(yōu)化中提供一個大致的方向。

          performance面板

          performance1.jpg

          performance面板會給我們提供一個具體的執(zhí)行過程,從HTML文檔下載,解析HTML,到解析CSS,計算樣式,執(zhí)行JS。

          火焰圖

          performance2.jpg

          從火焰圖我們可以找到長任務(wù),分析長任務(wù),或者找到某些無關(guān)緊要的任務(wù)把他們拆分,延后,優(yōu)化使他們達(dá)到一個理想狀態(tài)。

          performance monitor面板

          pm1.jpg

          performance monitor讓我們監(jiān)控內(nèi)存和CPU的占用,它給出的是整體的占用數(shù)據(jù),可以用來觀察某一段代碼某一個特效會不會造成性能影響。

          webpack-bundle-analyze

          wba.gif

          如果你用到了webpack打包,可以用它來分析打包后的文件,做成具體策略。

          從輸入一個URL談起

          這是一個URL為了見到你穿越無數(shù)路由器的感人故事。

          DNS查詢

          與服務(wù)器交互首先要進(jìn)行DNS查詢,得到服務(wù)器的IP地址,瀏覽器會首先查詢自己的緩存,之后會查詢本地HOSTS,如果仍然沒找到會發(fā)起向DNS服務(wù)器查詢的請求。

          在這里我們可以做的優(yōu)化不多,DNS是我們相對不可控的一個條件,但我們?nèi)匀豢梢宰龅囊粋€優(yōu)化策略是預(yù)查詢。

          進(jìn)行DNS預(yù)查詢

          在文檔頂部我們可以將我們即將要請求的地址的DNS預(yù)先查詢,通過插入一個link標(biāo)簽

          來告知瀏覽器我們將要從這個地址(通常會是存放靜態(tài)資源的CDN的地址,)拉取數(shù)據(jù)了,你先查詢一下,當(dāng)用到的時候就可以直接拿到對應(yīng)的IP。

          dns-prefetch[1]

          建立HTTP(TCP)連接

          得到服務(wù)器IP之后,首先進(jìn)行三次握手,之后會進(jìn)行SSL握手(HTTPS),SSL握手時會向服務(wù)器端確認(rèn)HTTP的版本。

          針對這方面的優(yōu)化,前端可做的事情不多,主要是服務(wù)器端的事情,不過仍然要了解一下前端可以看得到的策略。

          keep-alive

          由于TCP的可靠性,每條獨(dú)立的TCP連接都會進(jìn)行一次三次握手,從上面的Network的分析中可以得到握手往往會消耗大部分時間,真正的數(shù)據(jù)傳輸反而會少一些(當(dāng)然取決于內(nèi)容多少)。HTTP1.0和HTTP1.1為了解決這個問題在header中加入了Connection: Keep-Alivekeep-alive的連接會保持一段時間不斷開,后續(xù)的請求都會復(fù)用這一條TCP,不過由于管道化的原因也會發(fā)生隊頭阻塞的問題。

          HTTP1.1默認(rèn)開啟Keep-Alive,HTTP1.0可能現(xiàn)在不多見了,如果你還在用,可以升級一下版本,或者帶上這個header。

          connection keep-alive[2]

          HTTP2

          HTTP2相對于HTTP1.1的一個主要升級是多路復(fù)用,多路復(fù)用通過更小的二進(jìn)制幀構(gòu)成多條數(shù)據(jù)流,交錯的請求和響應(yīng)可以并行傳輸而不被阻塞,這樣就解決了HTTP1.1時復(fù)用會產(chǎn)生的隊頭阻塞的問題,同時HTTP2有首部壓縮的功能,如果兩個請求首部(headers)相同,那么會省去這一部分,只傳輸不同的首部字段,進(jìn)一步減少請求的體積。

          Nginx開啟HTTP2的方式特別容易,只需要加一句http2既可開啟:

          server?{
          ?listen?443?ssl?http2;?#?加一句?http2.
          ?server_name?domain.com;
          }
          復(fù)制代碼

          成本低廉,效果巨大。

          HTTP2[3]

          緩存

          緩存通過復(fù)用之前的獲取過的資源,可以顯著提高網(wǎng)站和應(yīng)用程序的性能,合理的緩存不僅可以節(jié)省巨大的流量也會讓用戶二次進(jìn)入時身心愉悅,如果一個資源完全走了本地緩存,那么就可以節(jié)省下整個與服務(wù)器交互的時間,如果整個網(wǎng)站的內(nèi)容都被緩存在本地,那即使離線也可以繼續(xù)訪問(很酷,但還沒有完全很酷)。

          HTTP緩存主要分為兩種,一種是強(qiáng)緩存,另一種是協(xié)商緩存,都通過Headers控制。

          整體流程如下:

          cache.png

          強(qiáng)緩存

          強(qiáng)緩存根據(jù)請求頭的ExpiresCache-Control判斷是否命中強(qiáng)緩存,命中強(qiáng)緩存的資源直接從本地加載,不會發(fā)起任何網(wǎng)絡(luò)請求。

          Cache-Control的值有很多:

          Cache-Control:?max-age=
          Cache-Control:?max-stale[=]
          Cache-Control:?min-fresh=
          Cache-control:?no-cache
          Cache-control:?no-store
          Cache-control:?no-transform
          Cache-control:?only-if-cached
          復(fù)制代碼

          常用的有max-ageno-cacheno-store

          max-age?是資源從響應(yīng)開始計時的最大新鮮時間,一般響應(yīng)中還會出現(xiàn)age標(biāo)明這個資源當(dāng)前的新鮮程度。

          no-cache?會讓瀏覽器緩存這個文件到本地但是不用,Network中disable-cache勾中的話就會在請求時帶上這個haader,會在下一次新鮮度驗證通過后使用這個緩存。

          no-store?會完全放棄緩存這個文件。

          服務(wù)器響應(yīng)時的Cache-Control略有不同,其中有兩個需要注意下:

          1. public, public 表明這個請求可以被任何對象緩存,代理/CDN等中間商。
          2. private,private 表明這個請求只能被終端緩存,不允許代理或者CDN等中間商緩存。

          Expires是一個具體的日期,到了那個日期就會讓這個緩存失活,優(yōu)先級較低,存在max-age的情況下會被忽略,和本地時間綁定,修改本地時間可以繞過。

          另外,如果你的服務(wù)器的返回內(nèi)容中不存在ExpiresCache-Control: max-age,或?Cache-Control:s-maxage但是存在Last-Modified時,那么瀏覽器默認(rèn)會采用一個啟發(fā)式的算法,即啟發(fā)式緩存。通常會取響應(yīng)頭的Date_value - Last-Modified_value值的10%作為緩存時間,之后瀏覽器仍然會按強(qiáng)緩存來對待這個資源一段時間,如果你不想要緩存的話務(wù)必確保有no-cacheno-store在響應(yīng)頭中。

          協(xié)商緩存

          協(xié)商緩存一般會在強(qiáng)緩存新鮮度過期后發(fā)起,向服務(wù)器確認(rèn)是否需要更新本地的緩存文件,如果不需要更新,服務(wù)器會返回304否則會重新返回整個文件。

          服務(wù)器響應(yīng)中會攜帶ETagLast-ModifiedLast-Modified?表示本地文件最后修改日期,瀏覽器會在request header加上If-Modified-Since(上次返回的Last-Modified的值),詢問服務(wù)器在該日期后資源是否有更新,有更新的話就會將新的資源發(fā)送回來。

          但是如果在本地打開緩存文件,就會造成Last-Modified被修改,所以在HTTP / 1.1 出現(xiàn)了ETag

          Etag就像一個指紋,資源變化都會導(dǎo)致ETag變化,跟最后修改時間沒有關(guān)系,ETag可以保證每一個資源是唯一的

          If-None-Match的header會將上次返回的ETag發(fā)送給服務(wù)器,詢問該資源的ETag是否有更新,有變動就會發(fā)送新的資源回來

          ETag(If-None-Match)的優(yōu)先級高于Last-Modified(If-Modified-Since),優(yōu)先使用ETag進(jìn)行確認(rèn)。

          協(xié)商緩存比強(qiáng)緩存稍慢,因為還是會發(fā)送請求到服務(wù)器進(jìn)行確認(rèn)。

          CDN

          CDN會把源站的資源緩存到CDN服務(wù)器,當(dāng)用戶訪問的時候就會從最近的CDN服務(wù)器拿取資源而不是從源站拿取,這樣做的好處是分散了壓力,同時也會提升返回訪問速度和穩(wěn)定性。

          壓縮

          合理的壓縮資源可以有效減少傳輸體積,減少傳輸體積的結(jié)果就是用戶更快的拿到資源開始解析。

          壓縮在各個階段都會出現(xiàn),比如上面提到的HTTP2的首部壓縮,進(jìn)行到這一步的壓縮是指對整個資源文件進(jìn)行的壓縮。

          瀏覽器在發(fā)起請求時會在headers中攜帶accept-encoding: gzip, deflate, br,告知服務(wù)器客戶端可以接受的壓縮算法,之后響應(yīng)資源會在響應(yīng)頭中攜帶content-encoding: gzip告知本文件的壓縮算法。

          GZIP壓縮

          GZIP是非常常用的壓縮算法,現(xiàn)代客戶端都會支持,你可以在上傳文件時就上傳一份壓縮后的文件,也可以讓Nginx動態(tài)壓縮[4]

          進(jìn)行頁面渲染

          關(guān)鍵渲染路徑

          workflow.jpg

          關(guān)鍵渲染路徑是瀏覽器將HTML/CSS/JS轉(zhuǎn)換為屏幕上看到的像素內(nèi)容所經(jīng)過的一系列步驟。

          瀏覽器得到HTML后會開始解析DOM樹,CSS資源的下載不會阻塞解析DOM,但是也要注意,如果CSS未下載解析完成是會阻塞最終渲染的。

          從Performance面板中可以清晰的看到瀏覽器如何解析HTML的:

          parsehtml.jpg

          得到HTML后首先會解析HTML,然后解析樣式,計算樣式,繪制圖層等等操作,JS腳本運(yùn)行,之后可能會重復(fù)這一步驟。

          parsehtml2.jpg

          在這里前端可以做的事情多了起來,接下來自頂向下說起。

          渲染頁面[5]

          預(yù)加載/預(yù)連接內(nèi)容

          和前面說的DNS預(yù)查詢一樣,可以將即將要用到的資源或者即將要握手的地址提前告知瀏覽器讓瀏覽器利用還在解析HTML計算樣式的時間去提前準(zhǔn)備好。

          preload

          使用link的preload屬性預(yù)加載一個資源。

          "preload"?href="style.css"?as="style">
          復(fù)制代碼

          as屬性可以指定預(yù)加載的類型,除了style還支持很多類型,常用的一般是stylescript,css和js。

          其他的類型可以查看文檔:

          preload[6]

          prefetch

          prefetch和preload差不多,prefetch是一個低優(yōu)先級的獲取,通常用在這個資源可能會在用戶接下來訪問的頁面中出現(xiàn)的時候。

          當(dāng)然對當(dāng)前頁面的要用preload,不要用prefetch,可以用到的一個場景是在用戶鼠標(biāo)移入a標(biāo)簽時進(jìn)行一個prefetch。

          prefetch[7]

          preconnect

          preconnect和dns-prefetch做的事情類似,提前進(jìn)行TCP,SSL握手,省去這一部分時間,基于HTTP1.1(keep-alive)和HTTP2(多路復(fù)用)的特性,都會在同一個TCP鏈接內(nèi)完成接下來的傳輸任務(wù)。

          script加標(biāo)記

          當(dāng)瀏覽器解析至script標(biāo)簽時,瀏覽器的主線程就會等待script,或者運(yùn)行script,然后繼續(xù)開始構(gòu)建,在以前,如果你把script標(biāo)簽放到了文檔的最上面,那么在等待下載和運(yùn)行的這段時間內(nèi)頁面就會處于白屏和無法操作的狀態(tài),并且不是并行的下載,瀏覽器會逐個下載并運(yùn)行,這是一個相當(dāng)糟糕的體驗。所以都會選擇將script放在文檔底部,盡可能推后腳本的執(zhí)行時機(jī),不過并不完全可控。

          時至今日,我們可以給script標(biāo)簽增加標(biāo)記,使其異步(延遲)運(yùn)行,把可控權(quán)交給開發(fā)者。

          async標(biāo)記

          與async一樣,defer標(biāo)記告訴瀏覽器在等待js下載期間可以去干其他事,多條js可以并行下載,不過當(dāng)js下載完成之后不會立即執(zhí)行,而是會等待解析完整個HTML之后在開始執(zhí)行,而且多條defer標(biāo)記的js會按照順序執(zhí)行,


          復(fù)制代碼

          SSR

          利用服務(wù)器端優(yōu)先渲染出某一部分重要的內(nèi)容,讓其他內(nèi)容懶加載,這樣到達(dá)瀏覽器端時一部分HTML已經(jīng)存在,頁面上就可以呈現(xiàn)出一定的內(nèi)容,這里注意服務(wù)器端渲染出來的HTML部分最好不要超過14kb,TCP慢開始的規(guī)則讓第一個TCP包的大小是14kb,這是與網(wǎng)站交互會接受到的第一個包。

          更多優(yōu)化手段

          上面是目前所知的優(yōu)化手段~,更多的優(yōu)化待發(fā)掘中,路過的大哥們、小姐姐們還請給個贊??,有問題的也可留言交流~??。

          來自:HuberTRoy

          https://juejin.cn/post/6966857691381645325


          瀏覽 69
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲视频中文在线 | 操13| 国产精品第一操逼视频 | 抽插亚洲 | 国产在线播放日本 |