多圖站點(diǎn)性能優(yōu)化

完整高頻題庫(kù)倉(cāng)庫(kù)地址:https://github.com/hzfe/awesome-interview

完整高頻題庫(kù)閱讀地址:https://febook.hzfe.org/

回答關(guān)鍵點(diǎn)

圖片優(yōu)化 傳輸優(yōu)化 加載策略

提高網(wǎng)站性能的一項(xiàng)重要指標(biāo)是提高訪問(wèn)速度,這與用戶留存率和轉(zhuǎn)換率呈正相關(guān)。根據(jù) HTTPArchive 的數(shù)據(jù)可知,圖像是大多數(shù)網(wǎng)站需求最多的資源類型,通常比其他資源占用更多帶寬。在多圖站點(diǎn)中,圖片資源對(duì)于頁(yè)面的加載和整體的用戶體驗(yàn)有更明顯的影響。最常見(jiàn)的問(wèn)題是圖片加載慢。對(duì)應(yīng)的優(yōu)化策略包括:

  • 圖片優(yōu)化:進(jìn)行圖片壓縮/縮放和選擇正確的圖片格式。
  • 網(wǎng)絡(luò)傳輸優(yōu)化:使用 HTTP/2 和 CDN 服務(wù)。
  • 圖片加載策略優(yōu)化:按需使用懶加載、預(yù)加載,響應(yīng)式圖片加載等策略。

知識(shí)點(diǎn)深入

1. 圖片優(yōu)化

1.1 選擇合適的圖片格式

為控制篇幅,以下提到的圖片格式,為截止至 2021 年 8 月,市場(chǎng)份額大于 0.1% 的格式。

  1. JPEG 的壓縮效率高,是一種高效且輕巧的有損壓縮圖片格式。但不適合對(duì)矢量或?qū)Ρ榷葟?qiáng)的圖像壓縮,會(huì)有明顯的圖片質(zhì)量下降。超過(guò)一定的壓縮閾值,壓縮的圖像也會(huì)出現(xiàn)明顯的圖片質(zhì)量下降。

  2. PNG 是一種無(wú)損壓縮的高保真圖片格式。相比 JPEG 有更強(qiáng)色彩表現(xiàn)力,且支持透明通道。

  3. GIF 是一種最多支持 256 種顏色的 8 位無(wú)損圖片格式,支持動(dòng)圖。

  4. WebP 是一種同時(shí)提供有損壓縮與無(wú)損壓縮的圖片格式。不僅支持透明圖片,有優(yōu)秀的色彩表現(xiàn),也能支持動(dòng)畫。支持無(wú)損壓縮且通常比 PNG 格式的相同圖像小 26%。支持有損壓縮且比視覺(jué)上相似壓縮水平的 JPEG 圖像平均小 25-35%。但是瀏覽器兼容性差。

  5. SVG 是一種基于 XML 語(yǔ)法的圖像格式,全稱是可縮放矢量圖(Scalable Vector Graphics)。適合非照片類型的圖片的縮放或高保真場(chǎng)景。

圖中所示為 2012 年 1 月至 2021 年 8 月的主流圖片格式的使用趨勢(shì)。

圖片來(lái)源 w3techs.com

按需選擇更高效的圖片格式,不僅能提升用戶視覺(jué)體驗(yàn),也可以提升網(wǎng)站加載效率。在選用圖片格式時(shí),一般可以基于一些簡(jiǎn)單規(guī)則來(lái)篩選:在兼容性支持的情況下,可以選用 WebP,否則可以通過(guò)動(dòng)圖和透明度兩個(gè)需求點(diǎn)來(lái)進(jìn)行篩選:

  • 動(dòng)圖

    可以使用 GIF 或者是視頻格式。前者的問(wèn)題在于支持的色彩少,低幀率低分辨率,文件體積利用率低,而視頻方案則可以避免這些問(wèn)題。也可以使用 APNG,支持更多色彩的前提下,和對(duì)應(yīng) GIF 格式的文件體積相近。

  • 透明度

    PNG 和 GIF 都支持透明圖片,可以按需使用。

在沒(méi)有透明和動(dòng)畫需求的情況下,JPEG 格式圖片勝任大部分場(chǎng)景,如果對(duì)圖片的展示質(zhì)量有較高要求時(shí),可使用 PNG 格式圖片。

繪制 LOGO、ICON 等非照片的圖片內(nèi)容時(shí),一般使用 SVG 格式。比如 iconfont 等矢量圖標(biāo)管理平臺(tái)中大量使用 SVG 格式。

1.2 圖片壓縮和縮放處理

由于實(shí)際應(yīng)用場(chǎng)景的差異,對(duì)應(yīng)圖片的布局大小以及圖片細(xì)節(jié)要求各有不同,大量未經(jīng)壓縮或縮放調(diào)整的圖片會(huì)使網(wǎng)頁(yè)加載許多不必要的字節(jié),且對(duì)用戶的視覺(jué)效果沒(méi)有太大的提升。前端常見(jiàn)的壓縮和縮放的處理方案包括:

  • 靜態(tài)資源通過(guò)工具(比如 imagemin)按需進(jìn)行有損或無(wú)損壓縮。
  • 將用戶上傳的圖片繪制到 Canvas 畫布上,利用CanvasRenderingContext2D.drawImage(image, dx, dy, dWidth, dHeight) API 進(jìn)行圖片縮放;利用 HTMLCanvasElement.toDataURL(type, encoderOptions) API 進(jìn)行有損壓縮。
  • 根據(jù)用戶側(cè)的顯示需求(如頭像、縮略圖、商品圖等),通過(guò)對(duì)象存儲(chǔ)服務(wù)(如七牛、阿里云 OSS)所提供的壓縮或縮放等功能處理后返回使用。

2. 網(wǎng)絡(luò)傳輸優(yōu)化

2.1 使用 HTTP/2 協(xié)議

使用 HTTP/1.X 協(xié)議時(shí),瀏覽器有同源最大并發(fā)連接數(shù)的限制,且 HTTP/1.X 不支持多路復(fù)用,因此一個(gè)多圖站點(diǎn)想要獲得較完整的視覺(jué)呈現(xiàn),會(huì)有一定程度的延遲:所有的資源請(qǐng)求(包括圖片資源)會(huì)進(jìn)入先進(jìn)先出(FIFO)隊(duì)列等待被下載。

使用 HTTP/2 前的常見(jiàn)優(yōu)化方案包括:

  • 使用精靈圖 / 雪碧圖,減少 HTTP 請(qǐng)求數(shù)。
  • 10kb 大小以內(nèi)的圖片資源使用 base64 編碼,減少 HTTP 請(qǐng)求數(shù)。
  • 通過(guò)使用多個(gè)域名,開啟多個(gè) TCP 連接,突破瀏覽器同源最大并發(fā)連接數(shù)的限制。

由于 HTTP/2 支持多路復(fù)用,因此使用 HTTP/2 可以進(jìn)一步減少網(wǎng)絡(luò)延遲,更加快速的加載圖片資源。

如下圖所示,觀察 Connection ID 一列可知,使用 HTTP/2 的情況下,資源重用同一條 TCP 連接,并發(fā)請(qǐng)求大量圖片資源。

2.2 使用 CDN

CDN 將源站資源緩存到各加速節(jié)點(diǎn)后,用戶請(qǐng)求源站資源時(shí)無(wú)需回源,可就近獲取 CDN 節(jié)點(diǎn)上已緩存的資源,從而提高資源訪問(wèn)速度,分擔(dān)源站壓力。常見(jiàn)的 CDN 服務(wù)還支持對(duì)圖片進(jìn)行壓縮、縮放、裁剪等圖像處理功能。

3. 圖片加載策略優(yōu)化

3.1 圖片懶加載

懶加載的策略是推遲加載離屏圖片資源,從而減少資源請(qǐng)求數(shù)。實(shí)現(xiàn)懶加載的主流方案有:

  • 使用 img 標(biāo)簽的 loading 屬性。
  • 使用 Intersection Observer API。
  • 使用 scroll、resize 和 orientationchange 事件。

后兩種方案的實(shí)現(xiàn)原理是通過(guò)在 img 標(biāo)簽上添加 data-src 或其他自定義屬性存放圖片鏈接,而 src 屬性不被設(shè)置或設(shè)置為占位圖鏈接。通過(guò) Intersection Observer 或 scroll 等 API 檢測(cè)離屏圖片是否滾動(dòng)到預(yù)期位置,如果是則將 data-src 的值賦給 src 屬性,從而達(dá)到懶加載的目的。

一般使用圖片懶加載時(shí),圖片的占位處會(huì)使用各種方式來(lái)提升用戶體驗(yàn):

  • 色塊 / 骨架屏占位。
  • LOGO 等品牌元素做默認(rèn)圖片。
  • 使用圖片縮略圖做模糊效果占位。

img loading

從 Chrome 76+ 版本起,開發(fā)者可以使用 loading 屬性來(lái)推遲加載可通過(guò)滾動(dòng)進(jìn)入視口內(nèi)的離屏圖像。通過(guò)給 loading 屬性設(shè)置 lazy 值,可以推遲加載資源,直到它與視口達(dá)到一定距離。caniuse.com 可查閱跨瀏覽器兼容性支持的詳細(xì)信息。不支持 loading 屬性的瀏覽器會(huì)忽略該屬性,不會(huì)產(chǎn)生副作用。

<img?src="image.png"?loading="lazy"?alt="…"?width="200"?height="200"?/>

Intersection Observer

Intersection Observer API 可用于異步觀察目標(biāo)元素與祖先元素或與頂級(jí)文檔視口的交叉點(diǎn)變化。

<img?data-src="https://hzfe-blah.com/anyphoto1.jpg"?/>
<img?data-src="https://hzfe-blah.com/anyphoto2.jpg"?/>
const?config?=?{
??/**?any?option?*/
};

const?observer?=?new?IntersectionObserver(function?(entries,?self)?{
??entries.forEach(({?isIntersecting,?target?})?=>?{
????if?(isIntersecting)?{
??????if?(target.dataset.src)?{
????????target.src?=?target.dataset.src;
????????target.removeAttribute("data-src");
??????}

??????self.unobserve(target);
????}
??});
},?config);

const?images?=?document.querySelectorAll("[data-src]");
images.forEach((image)?=>?{
??observer.observe(image);
});

scroll

如果 Intersection Observer 存在兼容性問(wèn)題,除了可以添加對(duì)應(yīng) polyfill 之外,也可以考慮降級(jí)為監(jiān)聽 scroll、resize、orientationchange 事件的方案。實(shí)現(xiàn)思路和 Intersection Observer 一致。具體細(xì)節(jié)上,需要自行計(jì)算圖片節(jié)點(diǎn)與目標(biāo)視口的縱向或橫向距離,且需使用節(jié)流函數(shù)來(lái)避免性能問(wèn)題。

3.2 圖片預(yù)加載

圖片預(yù)加載機(jī)制是為了增強(qiáng)用戶體驗(yàn),盡快地加載出圖片,使得用戶體驗(yàn)更為流暢。

如果預(yù)加載的圖片是確切且有限的,可以通過(guò)硬編碼 link 標(biāo)簽來(lái)實(shí)現(xiàn)預(yù)加載。但是多數(shù)情況下,預(yù)加載的使用場(chǎng)景是動(dòng)態(tài)的。

link

<link rel="preload"> 允許開發(fā)者在 HTML 的 head 標(biāo)簽中聲明資源請(qǐng)求,指定頁(yè)面需要預(yù)加載的資源,并且在瀏覽器的主要渲染機(jī)制啟動(dòng)之前加載,避免阻塞頁(yè)面渲染且保證資源盡早可用。

<link?rel="preload"?as="image"?href="important.png"?/>

動(dòng)態(tài)場(chǎng)景

一般常見(jiàn)方案是動(dòng)態(tài)創(chuàng)建 Image 標(biāo)簽或者是 Ajax 請(qǐng)求。使用 Ajax 時(shí)需要注意可能存在跨域問(wèn)題。

//?動(dòng)態(tài)創(chuàng)建?Image
function?preloadImage(url)?{
??var?img?=?new?Image();
??img.src?=?url;
}

3.3 響應(yīng)式圖片加載

由于用戶終端設(shè)備不同,如果圖片資源無(wú)差別使用相同圖片,可能造成帶寬浪費(fèi)或者是圖片不清晰以及視覺(jué)體驗(yàn)差的問(wèn)題。

一般可以通過(guò)使用 picture 標(biāo)簽來(lái)定義零或多個(gè) source 節(jié)點(diǎn)和一個(gè) img 節(jié)點(diǎn),用于提供圖片在不同設(shè)備/顯示場(chǎng)景下對(duì)應(yīng)的內(nèi)容展示。picture 的常見(jiàn)作用包括:

  • 藝術(shù)指導(dǎo)(Art direction)

<picture>
??<source?srcset="hzfe-avatar-desktop.png"?media="(min-width:?990px)"?/>
??<source?srcset="hzfe-avatar-tablet.png"?media="(min-width:?750px)"?/>
??<img?src="hzfe-avatar.png"?alt="hzfe-default-avatar"?/>
</picture>
  • 提供圖片格式回退方案

    在支持的瀏覽器中優(yōu)先使用更適合的圖片格式,比如 WebP 等。同時(shí)支持在有兼容性問(wèn)題的瀏覽器中回退加載其他格式的圖片。

    <picture>
    ??<source?srcset="hzfe-avatar.webp"?type="image/webp"?/>
    ??<source?srcset="hzfe-avatar.jpg"?type="image/jpeg"?/>
    ??<img?src="hzfe-avatar.jpg"?alt="hzfe-default-avatar"?/>
    </picture>
  • 節(jié)省帶寬并提升頁(yè)面加載速度

    通過(guò)按需加載并顯示最適合用戶設(shè)備的圖像,從而節(jié)省帶寬和加快頁(yè)面加載時(shí)間。

    <picture>
    ??<source
    ????srcset="hzfe-avatar-desktop.png,?hzfe-avatar-desktop-2x.png?2x"
    ????media="(min-width:?990px)"??/>
    ??<source
    ????srcset="hzfe-avatar-tablet.png,?hzfe-avatar-tablet-2x.png?2x"
    ????media="(min-width:?750px)"??/>
    ??<img
    ????srcset="hzfe-avatar.png,?hzfe-avatar-2x.png?2x"
    ????src="hzfe-avatar.png"
    ????alt="hzfe-default-avatar"??/>
    </picture>

參考資料

  1. image types
  2. Fast load times
  3. Usage statistics of WebP for websites
  4. Browser-level image lazy-loading for the web

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容