Webp推出那年,我剛剛考上高中。轉眼間,大學畢業將近一年,我依舊是那個青蔥少年!就像Webp同樣,仍是那麼年輕,時至今日還沒有嶄露頭角,緣由是各大瀏覽器對它的兼容依舊不是那麼的友好。IE爸爸甚至至今都沒有要支持它的跡象。javascript
維基百科:WebP最初在2010年發佈,目標是減小文件大小,但達到和JPEG格式相同的圖片品質,但願可以減小圖片檔在網絡上的發送時間。 2011年11月8日,Google開始讓WebP支持無損壓縮和透明色(alpha通道)的功能,而在2012年8月16日的引用實作libwebp 0.2.0中正式支持。根據Google較早的測試,WebP的無損壓縮比網絡上找到的PNG檔少了45%的文件大小,即便這些PNG檔在使用pngcrush和PNGOUT處理過,WebP仍是能夠減小28%的文件大小。
簡單來講,Webp格式是一種圖片格式,它有更優秀的圖片壓縮算法,而且能實現肉眼難以辨識的質量差別,同時它還支持有損無損兩種壓縮模式。html
因爲是谷歌的親兒子,因此安卓原生瀏覽器對Webp的支持仍是比較樂觀的,Chrome桌面版和安卓版的支持也都比較好。國內的瀏覽器也不一樣程度的對Webp作了不少支持。我去Can I Use上截了張圖過來:java
因而可知,市面上佔有率比較大的瀏覽器對Webp的支持仍是很不錯的,因此有必要使用起來。實際上是以前無心間發現某寶和某東在使用,因此也想在這塊作一些優化。ios
有圖有真相,先看看優化後的效果吧。nginx
使用前:
使用後:
能夠很明顯的看到,僅僅這八張並非特別大的圖片,便節省了59.3K的流量。下載時間也有明顯的縮短。若是你的web項目是相似於某寶某東那樣有着大量圖片,那麼這塊節省的流量可想而知!web
市面上有一些圖片格式轉換工具,我這裏就不一一列舉了。這裏要講的多是比較簡單的一種使用方式,由於咱們的圖片等資源文件託管在阿里雲oss上,它只須要你在請求url裏面帶個參數,就會自動返回你想要的圖片格式。各位看官,若是大家的狀況和我不同,可能須要本身對圖片作一部分處理或者別的雲存儲也有相似的解決方案。算法
好的,言歸正傳,接下來講說個人解決方案。咱們的Web是利用Vue實現的先後端同構的,因此存在服務端渲染和客戶端渲染兩種狀況,這就要求咱們要分別在服務端和客戶端對瀏覽器是否支持Webp做出判斷,若是瀏覽器支持,就去oss取webp格式的圖片,不然繼續使用本來圖片格式。canvas
我所採起的方法是在封裝網絡請求的時候,作了一步判斷,而後把是否支持Webp的變量放到了環境變量中。因爲網絡請求須要同時支持客戶端和服務端,因此我採用的是axios並本身作了一層封裝。axios
// 封裝axios createRequest = (req) => { // 若是在客戶端建立 if (process.client) { process.env.supportWebp = document.createElement('canvas').toDataURL('image/webp').indexOf('data:image/webp') === 0 } else { // 從服務端檢測客戶端是否支持webp if (req && req.headers) { process.env.supportWebp = req.headers.accept.indexOf('image/webp') > -1 }else{ process.env.supportWebp = false } } }
其實不管是客戶端仍是服務端,均可以採用判斷accept裏面是否帶有'image/webp'的方式,可是有些童鞋說判斷accept方式有些瀏覽器不許確,因此咱們在客戶端採用較爲穩妥的方式去判斷。後端
每一個人的框架或者環境可能不一樣,因此代碼不必定能照搬,只需理解這部分的思想:根據不一樣的環境判斷瀏覽器是否支持Webp。
在使用的時候,對於頁面中的img,我寫了一個過濾器:
<img :src="item.image_url | checkWebp">
export function judgeWebp (src) { if(process.env.supportWebp + '' === 'true'){ return src + '?x-oss-process=image/format,webp' } return src } const filters = { //......, judgeWebp } Object.keys(filters).forEach(key => { Vue.filter(key, filters[key]) })
對於背景圖片,style動態綁定彷佛是不能使用過濾器的,因此採用計算屬性的方式實現。各位看官若是有更好的方法歡迎提出來。
到此爲止,咱們能夠根據瀏覽器是否支持webp來獲取到不一樣格式的圖片了。另外,有些社區也有過利用第三方polyfill來實現瀏覽器兼容Webp的方案。可是彷佛並非那麼的流行,追求穩妥的狀況下,我這裏暫不使用,若是你有過相似的實踐,歡迎與我分享。
webp的分享就到這裏,接下來咱們簡單聊聊http緩存。http緩存大體分爲兩類,一類是強制緩存,另外一類叫對比緩存。這兩種緩存方式是能夠同時存在的。強制緩存,一聽這名字就威武霸氣,因此它的優先級也是比較高的,就是說,若是強制緩存生效,對比緩存就再也不執行。另外一個區別點就是,強制緩存若是生效,就再也不和服務器交互了,對比緩存則須要每次都和服務器交互協商。
先說強制緩存。瀏覽器向服務器請求數據,返回的header頭中會攜帶緩存規則。體如今Expires和Cache-Control這兩個屬性當中。
Expires是HTTP 1.0的東西,能夠說是歷史遺留產物了。它的值是到期時間,若是請求時間小於這個到期時間,就會採用緩存。咱們一眼就能發現這個邏輯其實意義並不大,並且若是服務端和客戶端時間不一致,會有偏差產生。
Cache-Control彷佛是爲彌補Expires的天生缺陷而生的。它倆若是同時存在,Expires則不會生效。它的取值能夠爲:
取值 | 含義 |
---|---|
private | 可被緩存,但不能在用戶之間共享 |
public | 可被緩存,而且在多用戶間共享 |
no-store | 不緩存 |
no-cache | 使用對比緩存與服務器交互 |
max-age=xxx | 設定緩存有效期(單位秒) |
這裏須要區別no-store和no-cache,謹記no-store是不作緩存,而no-cache是使用對比緩存。彷佛翻譯過來很像,可是實際效果差不少,對於no-store這種不緩存,除非特殊狀況,咱們通常不使用。
咱們再聊聊對比緩存。對比緩存主要分兩大塊,一起是根據修改時間判斷緩存是否生效,另外一塊是經過Etag(我的理解就是個hash值)來判斷。
Last-Modified是存在於返回的header中的,顧名思義,它告訴咱們這個資源的最後修改時間。當瀏覽器再次發起請求的時候,會由If-Modified-Since帶着這個值到服務器去作對比,若是服務器發現這個值小於目前服務器上資源的Last-Modified,則會把新的文件返回,狀態碼200。若是大於等於則只返回攜帶304狀態碼的請求,通知瀏覽器這個值還沒有失效。
它的缺點是這裏的時間值只能精確到秒。
Etag能夠理解爲服務器給資源打的hash值,就相似於咱們使用構建工具打包資源文件後面會跟一條經常的字符串同樣,它保證資源文件的惟一性。Etag隨response返回給瀏覽器,同理瀏覽器下一次請求會由If-None-Match攜帶Etag的值去到服務器做比對。若是發現這個值不存在,說明本地的資源文件已經失效,服務器返回新的資源文件給客戶端,狀態碼200。反之,返回304通知客戶端資源文件仍然生效。
相較於對比最後修改時間的策略,它的優勢在於能夠突破精確到秒的限制,另外若是咱們有一些按期更新的文件,可是資源內容不變,Etag的優點就更爲明顯了。
這裏要說起的一點是,當Last-Modified和Etag策略同時生效的時候,Etag的優先級更高。
原本是想記錄一下webp的,可是既然是優化,就順便寫了寫http緩存這塊的內容。除此以外,各位還能夠根據實際狀況合理配置cdn以及nginx等的緩存,以實現更好的用戶體驗。優化路上無止境,希望咱們都能往極致的方向去作。今天就聊到這兒,有什麼說錯的地方還請各位看官批評指正,但願你們多多指教!