性能優(yōu)化——圖片壓縮、加載和格式選擇

大家好,我是 法醫(yī)。
前言
相信大家都聽(tīng)說(shuō)過(guò) "258 原則(https://blog.csdn.net/weixin_42139375/article/details/83001248)" ,一個(gè)網(wǎng)站的性能好壞很大程度上會(huì)影響到用戶的體驗(yàn)。
在我經(jīng)歷的多個(gè)電商與大屏項(xiàng)目的優(yōu)化性能的項(xiàng)目后,我發(fā)現(xiàn)圖片資源的處理在網(wǎng)站性能優(yōu)化中有著舉足輕重的作用。
一般電商網(wǎng)站請(qǐng)求數(shù)據(jù)

在首屏加載的 145 個(gè)請(qǐng)求中圖片資源請(qǐng)求占到了 75% 以上,在所有請(qǐng)求靜態(tài)資源中圖片也占有著很大的比重??梢?jiàn)圖片優(yōu)化的重要性。
不過(guò)在認(rèn)識(shí)圖片優(yōu)化前我們先了解下二進(jìn)制位數(shù)與色彩呈現(xiàn)的關(guān)系。
二進(jìn)制位數(shù)與色彩
在計(jì)算機(jī)中,一般用二進(jìn)制數(shù)來(lái)表示像素。在不同的圖片格式中,像素與二進(jìn)制位數(shù)之間對(duì)應(yīng)的關(guān)系是不同的。一個(gè)像素對(duì)應(yīng)的二進(jìn)制位數(shù)越多,它能表示的顏色種類(lèi)就豐富,成像效果也就越精致,圖片所需的存儲(chǔ)空間相應(yīng)也會(huì)越大。

目前市場(chǎng)上優(yōu)化圖片資源的方式有很多,如壓縮圖片、選擇正確格式、 CDN 加速、懶加載等。
壓縮圖片
壓縮圖片相信是大家第一時(shí)間想到的方案。像我們比較熟悉的 tinpng (https://tinypng.com/),他的原理是通過(guò)有"選擇性"地減少圖像所要存儲(chǔ)的顏色數(shù)量,來(lái)減少圖片所要存儲(chǔ)的內(nèi)存。
“When you upload a PNG (Portable Network Graphics) file, similar colors in your image are combined. This technique is called “quantization”. By reducing the number of colors, 24-bit PNG files can be converted to much smaller 8-bit indexed color images.

下面我們來(lái)看下樣例:

細(xì)節(jié)展示:

圖片格式
壓縮圖片雖然在一定程度上可以減少我們請(qǐng)求的資源所需要的帶寬,但如果是用對(duì)了格式在性能上往往會(huì)有質(zhì)的改變。
JPEG / JPG
JPEG 是最常用的圖像文件格式。
優(yōu)勢(shì)
支持極高的壓縮率,可使文件傳輸、下載、預(yù)覽速度大大加快。
利用可變的壓縮比可以控制文件大小。
能夠輕松地處理 1600 萬(wàn)種顏色,可以很好地再現(xiàn)全彩色的圖像。
缺陷
JPG 的有損壓縮在輪播圖和背景圖的展示上確實(shí)很難看出破綻,但當(dāng)它處理矢量圖形和 Logo 等線條感較強(qiáng)、顏色對(duì)比強(qiáng)烈的圖像時(shí),人為壓縮導(dǎo)致的圖片模糊會(huì)相當(dāng)明顯。因此不適宜用該格式來(lái)顯示高清晰度和線條感較強(qiáng)的圖像。
除此之外, JPG 并不支持對(duì)有透明度要求的圖像進(jìn)行顯示,如果需要顯示透明圖片還是需要另尋它路。

業(yè)務(wù)場(chǎng)景
JPG 適用于呈現(xiàn)色彩豐富的圖片,在我們?nèi)粘i_(kāi)發(fā)中,JPG 圖片經(jīng)常作為大的背景圖、輪播圖或 預(yù)覽圖出現(xiàn)。打開(kāi)某電商網(wǎng)站首頁(yè),即可看到大圖片的處理幾乎都是使用了 JPG。

PNG - 8 與 PNG - 24
png 是一種采用無(wú)損壓縮算法的位圖格式。
優(yōu)勢(shì)
無(wú)損壓縮 完全支持 alpha 透明度。 可以重復(fù)保存且不降低圖像質(zhì)量。
缺點(diǎn)
體積太大

業(yè)務(wù)場(chǎng)景
理論上來(lái)說(shuō),當(dāng)你追求最佳的顯示效果(詳情展示圖、圖片有放大需求、攝影作品等),并且不在意存儲(chǔ)大小或所需帶寬時(shí),可以使用 PNG-24 (https://baike.baidu.com/item/PNG/174154?fr=aladdin)。但實(shí)踐當(dāng)中,為了避免文件體積過(guò)大的問(wèn)題,我們一般不用 PNG 去處理較復(fù)雜的圖像。當(dāng)我們遇到適合 PNG 的場(chǎng)景時(shí),也會(huì)優(yōu)先選擇更為小巧的 PNG-8 。
亦或者需要處理有透明度或線條明顯的圖片時(shí),也會(huì)采用 PNG 。如網(wǎng)站主 logo:

SVG
嚴(yán)格來(lái)說(shuō)應(yīng)該是一種開(kāi)放標(biāo)準(zhǔn)的矢量圖形語(yǔ)言。
優(yōu)點(diǎn)
可縮放,可支持無(wú)限放大 可編程
缺點(diǎn)
不是所有的瀏覽器都支持 SVG,IE8 和早期版本都需要一個(gè)插件。
復(fù)雜的圖片會(huì)降低渲染速度(只支持小圖)。

業(yè)務(wù)場(chǎng)景
SVG 是文本文件,我們既可以像寫(xiě)代碼一樣定義 SVG ,把它寫(xiě)在 HTML 里、成為 DOM 的一部分。用的比較多的就是 iconfont (https://www.iconfont.cn/)。我們可以通過(guò)設(shè)置模塊的 fill 屬性輕松適配圖標(biāo)的換膚功能,并通過(guò) font-size 調(diào)節(jié)其大小。

Base64
一種基于 64 個(gè)可打印字符來(lái)表示二進(jìn)制數(shù)據(jù)的方法。
優(yōu)點(diǎn)
減少網(wǎng)絡(luò)請(qǐng)求 對(duì)于動(dòng)態(tài)實(shí)時(shí)生成的圖片無(wú)需將圖片存儲(chǔ)在服務(wù)器占用服務(wù)器資源
缺點(diǎn)
只適于小圖。 若需要頻繁替換的圖片需要整個(gè)代碼替換,可維護(hù)性低。
業(yè)務(wù)場(chǎng)景
Base64 和雪碧圖一樣,是作為小圖標(biāo)解決方案而存在的。
“Base64 是一種用于傳輸 8Bit 字節(jié)碼的編碼方式,通過(guò)對(duì)圖片進(jìn)行 Base64 編碼,我們可以直接將編碼結(jié)果寫(xiě)入 HTML 或者寫(xiě)入 CSS ,從而減少 HTTP 請(qǐng)求的次數(shù)。
在 Elements 中搜索 “base64” 關(guān)鍵字,你會(huì)發(fā)現(xiàn) Base64 也有很多使用的地方。而且它對(duì)應(yīng)的圖片占用內(nèi)存較小。
既然 Base64 這么棒,我們把所有圖片都用Base64 好了嘛。
Base64 編碼后,圖片大小會(huì)膨脹為原文件的 4/3( Base64 編碼原理 (https://blog.csdn.net/wo541075754/article/details/81734770))。如果我們把大圖也編碼到 HTML 或 CSS 文件中,后者的體積會(huì)明顯增加,即便我們減少了 HTTP 請(qǐng)求,也無(wú)法彌補(bǔ)這龐大的體積帶來(lái)的性能開(kāi)銷(xiāo)。也就是說(shuō)我們犧牲的渲染性能大于資源請(qǐng)求性能,這樣做不太值得。
我們可以看到,大多數(shù)用 Base64 編碼的圖片都是小圖。

WebP
一種同時(shí)提供了有損壓縮與無(wú)損壓縮(可逆壓縮)的圖片文件格式。
優(yōu)點(diǎn)
支持有損無(wú)損
占用體積小
可支持透明
缺點(diǎn)
兼容性不好


業(yè)務(wù)場(chǎng)景
同 JPEG/JPG 。因?yàn)槟壳凹嫒菪圆缓?,一般搭?nbsp;JPEG/JPG 一起使用。

圖片格式小結(jié)
給大家整理了思維導(dǎo)圖:

OSS 搭配 CDN
我們?cè)嫉姆绞绞菍D片等資源一起放入項(xiàng)目中打包上線。

這樣做的缺點(diǎn)在于打包出來(lái)的包大不說(shuō),用戶請(qǐng)求資源的速度也會(huì)受到限制。比如我們的服務(wù)器在華南,華北的用戶請(qǐng)求就會(huì)稍慢。當(dāng)遇到并發(fā)量大的情況時(shí),從部署服務(wù)器請(qǐng)求接口與資源這無(wú)外乎給我們的服務(wù)器提供了多余的壓力。當(dāng)我們臨時(shí)想替換一張圖片時(shí),也需要重新打包并發(fā)布上線,非常麻煩。

當(dāng)我們將圖片進(jìn)行 OSS 放置并 CDN 加速后,這個(gè)問(wèn)題就得到了很好的解決。不同地區(qū)的用戶可以訪問(wèn)就近服務(wù)器,重復(fù)的請(qǐng)求也會(huì)產(chǎn)生緩存,避免 OSS 流量的浪費(fèi)。
《OSS 和 CDN 的區(qū)別》(https://www.cnblogs.com/jsfh/p/14076992.html) 大家也可以參考這篇文章進(jìn)行細(xì)看。
圖片的懶加載
相信大家一定會(huì)遇到首屏數(shù)據(jù)過(guò)多加載緩慢的情況。在這個(gè)情況下我們就需要考慮懶加載了。當(dāng)用戶滾動(dòng)到預(yù)覽位置時(shí),在進(jìn)行圖片數(shù)據(jù)的請(qǐng)求。期間用骨架屏或縮略圖代替。
window.onload = function () {
// 獲取圖片列表,即 img 標(biāo)簽列表
var imgs = document.querySelectorAll('img');
// 獲取到瀏覽器頂部的距離
function getTop(e) {
return e.offsetTop;
}
// 懶加載實(shí)現(xiàn)
function lazyload(imgs) {
// 可視區(qū)域高度
var h = window.innerHeight;
// 滾動(dòng)區(qū)域高度
var s = document.documentElement.scrollTop || document.body.scrollTop;
for (var i = 0; i < imgs.length; i++) {
//圖片距離頂部的距離大于可視區(qū)域和滾動(dòng)區(qū)域之和時(shí)懶加載
if ((h + s) > getTop(imgs[i])) {
// 真實(shí)情況是頁(yè)面開(kāi)始有2秒空白,所以使用 setTimeout 定時(shí) 2s
(function (i) {
setTimeout(function () {
// 不加立即執(zhí)行函數(shù)i會(huì)等于9
// 隱形加載圖片或其他資源,
// 創(chuàng)建一個(gè)臨時(shí)圖片,這個(gè)圖片在內(nèi)存中不會(huì)到頁(yè)面上去。實(shí)現(xiàn)隱形加載
var temp = new Image();
temp.src = imgs[i].getAttribute('src');//只會(huì)請(qǐng)求一次
// onload 判斷圖片加載完畢,真是圖片加載完畢,再賦值給 dom 節(jié)點(diǎn)
temp.onload = function () {
// 獲取自定義屬性 src,用真圖片替換假圖片
imgs[i].src = imgs[i].getAttribute('src')
}
}, 2000)
})(i)
}
}
}
lazyload(imgs);
// 滾屏函數(shù)
window.onscroll = function () {
lazyload(imgs);
}
}
尾聲
性能優(yōu)化是我們前端開(kāi)發(fā)工程師必須要掌握的一門(mén)硬技能。和學(xué)習(xí)其他新技術(shù)不同的是,當(dāng)你想學(xué)習(xí)一套新的框架時(shí),閱讀文檔和源碼幾乎可以讓你在使用過(guò)程中游刃有余。但性能優(yōu)化卻不一樣,它只能讓我們?nèi)ッ魅ヮI(lǐng)悟去突破,它是一種經(jīng)驗(yàn)也是一種習(xí)慣更是一種嗅覺(jué)。
參考資料
最佳實(shí)踐:使用阿里云 CDN 加速 OSS 訪問(wèn) (https://developer.aliyun.com/article/770616?utm_content=g_1000173381)
掘金小冊(cè): 前端性能優(yōu)化原理與實(shí)踐 (https://juejin.cn/book/6844733750048210957)
壁紙網(wǎng)站: wellhaven (https://wallhaven.cc/)
RECOMMEND
