前言:
咱们的应用能够分为两部分,一部分是属于主进程的(包括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才能看到和修改。