前言:
咱們的應用能夠分爲兩部分,一部分是屬於主進程的(包括js(同步,異步),以及dom渲染等等),在一個時刻點,只能執行一個,要麼先去渲染dom,完了再去執行js;要麼執行完js,在去渲染dom,而不能同時執行js和dom渲染。 另外一部分屬於worker進程,它從新在後臺起了一個進程,它和應用的主進程互不影響,能夠同時執行。css
常見的worker有,web worker, service worker, shared worker等等。html
其中service worker通常做爲web應用程序、瀏覽器和網絡(若是可用)之間的代理服務。他們旨在建立有效的離線體驗,攔截網絡請求,以及根據網絡是否可用採起合適的行動,更新駐留在服務器上的資源。他們還將容許訪問推送通知和後臺同步API。用來構建PWA 應用
使用service-worker前,咱們必需要先在主進程中註冊它,而後才能在service-worker進程中編寫邏輯。vue
主進程react
//index.js if ("serviceWorker" in navigator) { // Use the window load event to keep the page load performant window.addEventListener("load", () => { navigator.serviceWorker.register("/service-worker.js").then(registration=>{ console.log("register succces...") }, err=>{ console.log("register error...",err) }); }); }
service-worker進程jquery
//service-worker.js console.log('Hello from service-worker.js');
service-worker的語法簡介在service-worker.js中,self/this 表示 ServiceWorkerGlobalScope, 即全局的serviceworker工做環境,至關於在主進程中的window。在此文件中,js的其餘api沒法使用,如DOM,BOM操做等,可是大部分的js api可用,同時ES6也可使用。webpack
在service-worker中能夠定義監聽事件,而後在對應事件中進行邏輯處理。web
具體api可查看 service worker MDNchrome
service-worker進程的執行流程npm
//在service worker中監聽install this.addEventListener('install', function(event) { event.waitUntil( caches.open('v1').then(function(cache) { return cache.addAll([ '/sw-test/', '/sw-test/index.html', '/sw-test/style.css', '/sw-test/app.js', '/sw-test/image-list.js', '/sw-test/star-wars-logo.jpg', '/sw-test/gallery/', '/sw-test/gallery/bountyHunters.jpg', '/sw-test/gallery/myLittleVader.jpg', '/sw-test/gallery/snowTroopers.jpg' ]); }) ); });
除了 install以外,還有 activate,message,fetch,sync,push等事件。json
打開chrome瀏覽器的application->service workers,會看到
能夠看到status爲 actived and is running,代表service-worker已經安裝成功了。
在service-worker中經過監聽事件,而後編寫對應的邏輯並非一件容易的事,尤爲對於文件緩存,可能npm run build後,名稱隨時會變。
因此chrome官方推出了wokbox框架
wokbox 是用於向web應用程序添加離線支持的JavaScript庫。
要使用wokbox,只需在service-worker.js文件中引入workbox-sw.js便可,而後會自動的在service-worker.js中建立workbox對象,
importScripts('https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js'); if (workbox) { console.log(`Yay! Workbox is loaded 🎉`); } else { console.log(`Boo! Workbox didn't load 😬`); }
在wokbox對象中,包含不少模塊,好比 workbox.routing模塊,workbox.precaching模塊,workbox.strategies模塊,workbox.expiration模塊等等,它們分別負責處理不一樣的邏輯。
//緩存文件 workbox.routing.registerRoute( /\.css$/, //經過正則匹配須要緩存哪些文件 new workbox.strategies.StaleWhileRevalidate({ cacheName: 'css-cache', //緩存名,可在application-> Cache storage下找到 }) ); workbox.routing.registerRoute( /\.(?:js)$/, new workbox.strategies.CacheFirst({ cacheName: 'js-cache', plugins: [ //設置過時時間和最大數量 new workbox.expiration.Plugin({ maxEntries: 20, maxAgeSeconds: 7 * 24 * 60 * 60, }) ], }) );
workbox.routing.registerRoute代表 當service-worker在安裝以後,當頁面有發送對應http請求時,開始緩存。
而下面的workbox.precaching.precacheAndRoute能夠在service-worker在安裝以前,就把對應文件預先緩存下來。
workbox.precaching.precacheAndRoute([ "/app.0.css", "/app.bundle.js", { url: "/start.html", revision: "dd75b1ef1ac2d4726b03fe46e90423f1" } ]);
此時咱們在chrome下的 application->cache storage,會看到
緩存的名稱,和緩存的文件列表
首先了解下處理路由的workbox的策略
workbox.routing.registerRoute( '/logo.png', //匹配字符串路由 new workbox.strategies.NetworkFirst() //採用NetworkFirst策略 );
workbox.routing.registerRoute( /\.js$/, // 配置 正則 路由, new workbox.strategies.StaleWhileRevalidate(), //採用StaleWhileRevalidate策略 );
//緩存第三方,好比jquery, 則策略最好使用NetworkFirst或者StaleWhileRevalidate, 不要使用CacheFirst workbox.routing.registerRoute( 'https://cdn.bootcss.com/jquery/3.4.1/jquery.js', new workbox.strategies.StaleWhileRevalidate(), //new workbox.strategies.NetworkFirst(), ); //若是非要使用CacheFirst策略,則使用workbox.cacheableResponse.Plugin限定 workbox.routing.registerRoute( 'https://cdn.bootcss.com/jquery/3.4.1/jquery.js', new workbox.strategies.CacheFirst({ plugins: [ new workbox.cacheableResponse.Plugin({ statuses: [0, 200] }) ] }), );
//還能夠自定義策略的名稱,過時時間等等 workbox.routing.registerRoute( /\.(?:js)$/, new workbox.strategies.CacheFirst({ cacheName: 'js-cache', plugins: [ new workbox.expiration.Plugin({ maxEntries: 20, maxAgeSeconds: 7 * 24 * 60 * 60, }) ], }) );
在前面咱們看到 cache的名稱爲 workbox-precache-v2-http://127.0.0.1:8081/,下面咱們修改下
//最好寫在緊貼着importScripts workbox-sw.js的下面,若是寫在文件最後,則不生效。 workbox.core.setCacheNameDetails({ prefix: "my-app", suffix: "v1", precache: "custom-precache-name", runtime: "custom-runtime-name" });
importScripts("https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js"); importScripts("precache-manifest.7df9e91fe595ae52486747ebe221a710.js"); //強制在service worker中使用debug。這樣service worker中的log也能打印到chrome console上 workbox.setConfig({ debug: true });
yarn add workbox-webpack-plugin
//webpack.config.js: const WorkboxPlugin = require('workbox-webpack-plugin'); module.exports = { // Other webpack config... plugins: [ // Other plugins... new WorkboxPlugin.GenerateSW() ] };
而後執行
npm run build
此時在dist目錄下會自動生成precache-manifest.<revision>.js 和 service-worker.js文件(爲何名字是這個,不是sw.js,由於在註冊時register("/service-worker.js")寫的這個名字),如圖:
在precache-manifest.<revision>.js文件中,將預緩存列表經過全局變量self.__precacheManifest公開,以便在service-worker.js中調用。
默認會預緩存一切資源。
在service-worker.js中,則自動加載workbox cdn和 precache-manifest.<revision>.js文件,如圖:
瞬間感受方便了不少........
由於默認會預緩存一切資源,若是你不喜歡預緩存某些文件,如圖片,而在運行時緩存,則能夠在runtimeCaching中定製它們
// 這些選項幫助 ServiceWorkers 快速啓用 new WorkboxPlugin.GenerateSW({ // 在預緩存中排除 圖片 exclude: [/\.(?:png|jpg|jpeg|svg)$/], //定義運行時緩存(可接受多個json對象) runtimeCaching: [ { urlPattern: /\.(?:png|jpg|jpeg|svg)$/, // 在緩存時使用 StaleWhileRevalidate 策略. handler: "StaleWhileRevalidate", options: { // 定義緩存這些圖片的 cache名稱 cacheName: "my-images-cache", //配置 expiration expiration: { maxEntries: 10, maxAgeSeconds: 60 }, // 配置 background sync. backgroundSync: { name: "my-queue-name", options: { maxRetentionTime: 60 * 60 } }, //配置哪些響應被認爲是可緩存的 cacheableResponse: { statuses: [0, 200], headers: { "x-test": "true" } }, //配置廣播緩存更新插件。 broadcastUpdate: { channelName: "my-update-channel" }, //matchOptions和fetchOptions用於配置handler fetchOptions: { mode: "no-cors" }, matchOptions: { ignoreSearch: true } } } ], importWorkboxFrom: "cdn", //經過cdn加載workbox, 還可經過‘local’加載,這樣會將整個workbox下載到本地,再從本地引用 skipWaiting: false, // service worker是否應該跳過等待生命週期階段 clientsClaim: false, //service worker是否應該在任何現有客戶端激活後當即開始控制它 cacheId: "my-app-test", offlineGoogleAnalytics: true })
運行npm run build後,會看到自動生成以下的service-worker.js
若是沒出現,則只須要清空cache和service-worker文件便可,在clear storage中勾選unregister service workers和 cache storage,而後點擊clear site data便可清理,而後刷新頁面就會看到最新的service worker和cache storage。
咱們會發現無論vue仍是react,構建後,點開service-worker.js文件發現都和咱們剛纔自動生成的service-worker.js很是類似,不一樣的是,vue和react都把new WorkboxPlugin.GenerateSW部分封裝了起來,除非npm run eject才能看到和修改。