摘要:導入谷歌提供的庫注冊成功可以進行下一步的操作立即激活跳過等待下面用官網給出的幾張圖解釋一下所提供的幾種緩存策略而它們正好能滿足上文我們自己用代碼所實現的效果。接下來讓我們使用去實現上文優化前端性能的緩存策略。
前言 :
說起前端性能優化, 我們首先想到的可能就是用 Gulp 、Webpack 之類的自動化構建工具對 HTML、CSS 、JS 代碼進行壓縮,同時優化圖片資源。再者就是使用 CSS Sprite 或者對于較小的圖片用 base64 直接編碼來進行優化。當然還有很多可以優化的方向, 例如考慮瀏覽器緩存、頁面渲染性能 ( 減少重排與重繪和 GPU 硬件加速 ) 、JS阻塞性能等等。但我們今天講的是如何利用緩存策略在適宜的情況下直接減少對前端數據的請求量從而達到前端性能的優化。因此 Service Worker 以及其相關的 API 就成為了我們今天的主角。
提醒 : 本篇文章將直接講述如何利用 Service Worker 對前端性能進行優化, 希望讀者在此之前已經對 Service Worker 有基本的了解, 若之前沒有接觸過, 可以先看看以下的兩篇文章。
Service Worker ~ Google ( 墻 )
Service Worker 簡介
制定緩存策略首先, 既然是前端性能優化, 我們就需要想想該如何制定緩存策略才能達到理想的效果。我們可能有這樣的想法, 即對 CSS 、JS 等易更改文件優先使用網絡請求的數據, 而對于圖片資源則優先使用緩存。如果再進一步思考的話, 我們也許會希望在網絡條件好的情況下優先使用網絡請求數據, 而網絡條件較差時則盡可能的直接使用緩存。嗯 ~ 看起來還不錯, 那么根據以上的兩點我們先用代碼來實現一下吧。
先邁出最簡單的第一步, 注冊 Service Worker。
// index.js if ( "serviceWorker" in navigator ) { navigator.serviceWorker.register("/sw.js") .then( registration => { console.log("ServiceWorker registration successful with scope: ", registration.scope); }) .catch( err => console.log("ServiceWorker registration failed: ", err)); }
在 sw.js 中實現常規操作。
// sw.js var cacheMaps = { cache_file: "css.js", cache_image: "images" } self.addEventListener("install", () => { // 一般注冊以后,激活需要等到再次刷新頁面后再激活 // 可防止出現等待的情況,這意味著服務工作線程在安裝完后立即激活 self.skipWaiting(); }) // 運行觸發的事件 self.addEventListener("activate", event => { event.waitUntil( // 若緩存數據更改,則在這里更新緩存 caches.keys() .then( cacheNames => { return cacheNames.filter( item => !Object.values(cacheMaps).includes(item)) }) .then( keys => { return Promise.all( keys.map( key => { return caches.delete(key); })) }) // 更新客戶端上的 Service Worker 腳本 .then(() => self.clients.claim()) ) })
實現網絡優先的邏輯。
function firstNet(cacheName, request) { // 請求網絡數據并緩存 return fetch(request).then( response => { var responseCopy = response.clone(); caches.open(cacheName).then( cache => { cache.put(request, responseCopy); }); return response; }).catch(() => { return caches.open(cacheName).then( cache => { return cache.match(request); }); }); }
實現緩存優先的邏輯。
function firstCache(cacheName, request) { return caches.open(cacheName).then( cache => { return cache.match(request).then( response => { var fetchServer = function() { return fetch(request).then( newResponse => { cache.put(request, newResponse.clone()); return newResponse; }); } // 如果緩存中有數據則返回,否則請求網絡數據 if (response) { return response; } else { return fetchServer(); } }); }); }
完成緩存策略中我們提到的第一點,即對 CSS 、JS 請求使用網絡優先,圖片資源請求實現緩存優先。
// sw.js self.addEventListener("fetch", event => { var request = event.request, url = request.url, cacheName; // 網絡優先 if ( /.(js|css)$/.test(url) ) { (cacheName = cacheMaps.cache_file) && e.respondWith(firstNet(cacheName, request)); } // 緩存優先 else if ( /.(png|jpg|jpeg|gif|webp)$/.test(url) ) { (cacheName = cacheMaps.cache_image) && e.respondWith(firstCache(cacheName, request)); } })
接下來我們利用 Promise.race() 完成一個競速模式, 從而實現上文提到的第二點即根據網絡條件的好壞執行相應的操作。
function networkCacheRace(cacheName, request) { var timer, TIMEOUT = 500; /** * 網絡好的情況下給網絡請求500ms, 若超時則從緩存中取數據 * 若網絡較差且沒有緩存, 由于第一個Promise會一直處于pending, 故此時等待網絡請求響應 */ return Promise.race([new Promise((resolve, reject) => { timer = setTimeout(() => { caches.open(cacheName).then( cache => { cache.match(request).then( response => { if (response) { resolve(response); } }); }); }, TIMEOUT); }), fetch(request).then( response => { clearTimeout(timer); var responseCopy = response.clone(); caches.open(cacheName).then( cache => { cache.put(request, responseCopy); }); return response; }).catch(() => { clearTimeout(timer); return caches.open(cacheName).then( cache => { return cache.match(request); }); })]); }
現在我們可以在 sw.js 中更改一下緩存策略,從而達到最理想的效果。
// sw.js self.addEventListener("fetch", event => { // ... if ( /.(js|css)$/.test(url) ) { (cacheName = cacheMaps.cache_file) && e.respondWith(networkCacheRace(cacheName, request)); } // ... })更好的方案 : Workbox
什么是 Workbox ? 我們可以看看谷歌開發者官網中給出的解釋。
Workbox is a library that bakes in a set of best practices and removes the boilerplate every developer writes when working with service workers.
其大概意思是它對常見的 Service Worker 操作進行了一層封裝, 根據最佳實踐方便了開發者的使用。因此在我們快速開發自己的 PWA 應用時使用 Workbox 是最合適不過的了。
它主要有以下幾大功能 :
Precaching ~ 預緩存
Runtime caching ~ 運行時緩存
Strategies ~ 緩存策略
Request routing ~ 請求路由控制
Background sync ~ 后臺同步
etc ...
基于本文的內容, 在這里我們只談談如何簡單的使用 Workbox 以及它所提供的幾種緩存策略。
注意在 index.js 里面的注冊操作不會改變, 變化的是 sw.js 中的代碼。
// sw.js // 導入谷歌提供的 Workbox 庫 importScripts("https://storage.googleapis.com/workbox-cdn/releases/3.2.0/workbox-sw.js"); if ( !workbox ) { console.log(`Workbox didn"t load.`); return; } // Workbox 注冊成功, 可以進行下一步的操作 // 立即激活, 跳過等待 workbox.skipWaiting(); workbox.clientsClaim(); // workbox.routing.registerRoute()...
下面用官網給出的幾張圖解釋一下 Workbox 所提供的幾種緩存策略, 而它們正好能滿足上文我們自己用代碼所實現的效果。
Stale-While-Revalidate Cache First Network First Cache Only Network Only接下來讓我們使用 Workbox 去實現上文優化前端性能的緩存策略。
緩存優先 :
workbox.routing.registerRoute( /.(png|jpg|jpeg|gif|webp)$/, // 對于圖片資源使用緩存優先 workbox.strategies.cacheFirst({ cacheName: "images", // 設置最大緩存數量以及過期時間 plugins: [ new workbox.expiration.Plugin({ maxEntries: 60, maxAgeSeconds: 7 * 24 * 60 * 60, }), ], }), );
網絡優先 :
workbox.routing.registerRoute( /.(js|css)$/, workbox.strategies.staleWhileRevalidate({ cacheName: "css.js", }), );
由上文圖中可看出 stale-while-revalidate 策略與我們實現的網絡優先稍有不同, 確切的來說更加明智, 因為除了第一次需要網絡請求, 接下來的請求會直接從緩存中取數據但在頁面加載之后會立即更新緩存, 這樣既保證了加載速度又能每次將數據準確的更新到最新版本。
競速模式 :
workbox.routing.registerRoute( /.(js|css)$/, workbox.strategies.networkFirst({ // 給網絡請求0.5秒,若仍未返回則從緩存中取數據 networkTimetoutSeconds: 0.5, cacheName: "css.js", }), );
回頭看看我們手動實現的緩存策略, 顯然使用 Workbox 要簡單的多。當然 Workbox 中還有很多東西需要注意, 但由于已經超出了文章所講的主要內容因此在這里無法具體闡述, 建議讀者還是到官網去仔細看看文檔詳細了解一下,若因為墻的問題可以看看第二篇文章。
Workbox ~ Google ( 墻 )
神奇的 Workbox 3.0
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/95603.html
摘要:安裝后已經完成了安裝,并且等待其他的線程被關閉。激活后在這個狀態會處理事件回調提供了更新緩存策略的機會。并可以處理功能性的事件請求后臺同步推送。廢棄狀態這個狀態表示一個的生命周期結束。 showImg(https://segmentfault.com/img/bVbwWJu?w=2056&h=1536); 不知不覺,已經來到了最后的下篇 其實我寫的東西你如果認真去看,跟著去寫,應該能有...
摘要:前端每周清單專注前端領域內容,以對外文資料的搜集為主,幫助開發者了解一周前端熱點分為新聞熱點開發教程工程實踐深度閱讀開源項目巔峰人生等欄目。 前端每周清單專注前端領域內容,以對外文資料的搜集為主,幫助開發者了解一周前端熱點;分為新聞熱點、開發教程、工程實踐、深度閱讀、開源項目、巔峰人生等欄目。歡迎關注【前端之巔】微信公眾號(ID:frontshow),及時獲取前端每周清單;本文則是對于...
摘要:雖然有著各種各樣的不同,但是相同的是,他們前端優化不完全指南前端掘金篇幅可能有點長,我想先聊一聊閱讀的方式,我希望你閱讀的時候,能夠把我當作你的競爭對手,你的夢想是超越我。 如何提升頁面渲染效率 - 前端 - 掘金Web頁面的性能 我們每天都會瀏覽很多的Web頁面,使用很多基于Web的應用。這些站點看起來既不一樣,用途也都各有不同,有在線視頻,Social Media,新聞,郵件客戶端...
摘要:往往純的單頁面應用一般不會太復雜,所以這里不引入和等等,在后面復雜的跨平臺應用中我會將那些技術一擁而上。構建極度復雜,超大數據的應用。 showImg(https://segmentfault.com/img/bVbvphv?w=1328&h=768); React為了大型應用而生,Electron和React-native賦予了它構建移動端跨平臺App和桌面應用的能力,Taro則賦...
摘要:往往純的單頁面應用一般不會太復雜,所以這里不引入和等等,在后面復雜的跨平臺應用中我會將那些技術一擁而上。構建極度復雜,超大數據的應用。 showImg(https://segmentfault.com/img/bVbvphv?w=1328&h=768); React為了大型應用而生,Electron和React-native賦予了它構建移動端跨平臺App和桌面應用的能力,Taro則賦...
閱讀 2313·2021-11-08 13:13
閱讀 1244·2021-10-09 09:41
閱讀 1682·2021-09-02 15:40
閱讀 3185·2021-08-17 10:13
閱讀 2545·2019-08-29 16:33
閱讀 3121·2019-08-29 13:17
閱讀 3130·2019-08-29 11:00
閱讀 3295·2019-08-26 13:40