首先了解一下PWA(Progressive web apps,渐进式 Web 应用)
运用现代的 Web API
以及传统的渐进式加强策略来建立跨平台 Web
应用程序。 PWA的优势 PWA
是可被发现、易安装、可连接、独立于网络、渐进式、可重用、响应性和安全的。 PWA
中能够经过Service Worker
来实现离线的应用,这个也是PWA中一个比较重要的环节,它们主要应用到Web App中,已得到更好的体验,而且在如今也在大规模的应用。 Service Worker
是一个事件驱动worker
,运行在一个单独的后台进程,是PWA(ProgressiveWeb App)
运行的基础。主要用于代理网页请求,可缓存请求结果;可实现离线缓存功能,也拥有单独的做用域范围和运行环境。咱们之后把Service Worker
简称为SW
。javascript
本文大体分为:css
实例代码实例代码地址html
它们的运行在一个与咱们页面的 JavaScript 主线程独立的线程上
,而且没有对 DOM 结构
的任何访问权限。 这引入了与传统 Web 编程不一样的方法 - API 是非阻塞的
,而且能够在不一样的上下文之间发送和接收信息
。前端
SW
除了work
线程的限制外,因为可拦截页面请求,为了保证页面安全,浏览器端对sw
的使用限制也很多。java
window
、document
、parent
对象。能够访问navigator
、location
; SW
经过响应 postMessage
接口发送的消息来与其控制的页面通讯,页面可在必要时对 DOM
执行操做。sw.js
所在文件目录及子目录的请求可代理,可在注册时手动设置做用域范围;https
中使用,容许在开发调试的localhost
使用。能够经过查询service worker能够看到他在不一样平台或不一样浏览器中的兼容性。git
SW
的生命周期彻底独立于网页。 SW
为网页添加一个相似于 App
的生命周期,它只会响应系统事件,就算浏览器关闭时操做系统也能够唤醒 SW
,这点很是重要,让Web App
与 Native App
的能力变得相似了。因为是离线缓存,因此在初始安装时、更新它们的所走的生命周期是不相同。下面咱们就根据这两种场景结合代码来分析它的执行步骤。 SW
的生命周期大体分为:注册、更新、安装成功、安装失败、激活、销毁。github
使用SW前提条件web
https
中使用,容许在开发调试的localhost
使用。初始安装时大体流程大体以下图: 正则表达式
大体能够分为注册SW => 安装SW => 激活 => 空闲 => (缓存和返回请求/终止)
,在初始安装时会大体分为这几个步骤,下面就按照这几个步结合代码实现。chrome
用户首次访问SW控制的网站或页面时,sw.js
会马上被下载和解析。咱们要在页面中写入JavaScript
来注册SW
。
// 判断浏览器是否支持serviceWorker
if ('serviceWorker' in navigator) {
// 在页面加载后
window.addEventListener('load', function () {
// 经过navigator.serviceWorker.register 注册'./sw.js
navigator.serviceWorker.register('./sw.js')
.then(reg => { //注册成功
console.log('注册成功', reg)
}).catch(err => { //注册成功
console.log('注册失败', err)
})
});
} else {
console.log('当前浏览器不支持SW')
}
复制代码
首先检浏览器是否支持SW,若是支持就在浏览器加载后经过register().then
注册sw.js,而且设置注册成功或者失败的回调函数。
注意:
register()
方法的精妙之处在于服务工做线程文件的位置。SW
降接收此网域上全部的事项的featch
事件。 若是是Chrome浏览器能够经过chrome://inspect/#service-workers
或者console => application => Service Worker
查看是否注册成功
由于如今sw.js
中咱们的代码是空的,因此在浏览器中的cache stoage
是空的,运行效果以下:
在受控页面启动注册流程后,下面就是SW获取的第一个事件install
,而且只发生一次。传递到 installEvent.waitUntil()
的一个 promise
可代表安装的持续时间以及安装是否成功。
在install
中要作三件事打开缓存、缓存文件、确认全部须要的资产是否已缓存。
// 在sw.js中监听对应的安装事件,并预处理须要缓存的文件
// 该部份内容涉及到cacheStorage API
// 定义缓存空间名称
const CACHE_NAME = 'sw_cache_v1';
// 定义须要缓存的文件目录
let cachelist = ['./app.js', './index.css'];
// 监听安装事件,返回installEvent对象
self.addEventListener('install', function (installEvent) {
// waitUntil方法执行缓存方法
installEvent.waitUntil(
// cacheStorage API 可直接用caches来替代
// open方法建立/打开缓存空间,并会返回promise实例
// then来接收返回的cache对象索引
caches.open(CACHE_NAME)
// cache对象addAll方法解析(同fetch)并缓存全部的文件
.then(function(cache) {
console.log('Opened cache');
return cache.addAll(cachelist);
})
);
});
复制代码
第一个事件为install
,该事件在Worker
执行时当即触发。在install
的回调函数中,咱们经过caches.open(CACHE_NAME)
打开缓存,以后调用cache.addAll()
并传入路径数组。这是一个promise
链(caches.open()
和chaches.addAll()
。installEvent.waitUntill()
放大带有promise
并使用它来判断安装所花时间,以及是否安装成功。
注意: 第一个事件
install
,它只能被每一个 SW 调用一次。若是您更改您的 SW 脚本,则浏览器将其视为一个不一样的 SW,而且它将得到本身的install
事件。 若有任何文件没法下载,则安装步骤将失败。 当前的状态是在等待状态。 咱们能够直接经过self.skipwaiting()
让当前sw
当即将状态提高到active
。
当咱们安装成功时,效果以下图所示:
会多了一个skipWaiting
,还有在cache stroage
中的当前域名下的service worker
对应的缓存文件列表。这个时候咱们即便刷新也不会走service worker
的缓存的。
SW
准备控制客户端并处理 push
和 sync
等功能事件时,您将得到一个 activate
事件。但这不意味着调用 .register()
的页面将受控制。若是第二次加载此演示(换言之,刷新页面),该页面将受控制。改写代码sw.js
以下:
self.addEventListener('install', () => {
// 通常注册之后,激活须要等到再次刷新页面后再激活
// 可防止出现等待的状况,这意味着服务工做线程在安装完后当即激活
self.skipWaiting();
})
self.addEventListener('activate', function (event) {
event.waitUntil(
// cacheStorage API 可直接用caches来替代
// open方法建立/打开缓存空间,并会返回promise实例
// then来接收返回的cache对象索引
caches.open(CACHE_NAME)
// cache对象addAll方法解析(同fetch)并缓存全部的文件
.then(function(cache) {
console.log('Opened cache');
return cache.addAll(cachelist);
})
);
})
复制代码
通常在书写的时候,会在install()
注册以后直接经过self.skipWaiting();
激活当前的SW
,在activate
中书写打开缓存等等的逻辑,就不会出现上面还要刷新或者手动激活的问题。效果图以下:
可是若是出现更新SW,而且更新了缓存列表或者出现异步资源时,咱们能够经过clients.claim()
更新缓存列表。
激活 SW
后,您能够经过在其中调用 clients.claim()
控制未受控制的客户端。google developer中的一个异步加载图片的实例。下面修改代码以下:
self.addEventListener('install', (event) => {
event.waitUntil(
// cacheStorage API 可直接用caches来替代
// open方法建立/打开缓存空间,并会返回promise实例
// then来接收返回的cache对象索引
caches.open(CACHE_NAME)
// cache对象addAll方法解析(同fetch)并缓存全部的文件
.then(function(cache) {
console.log('Opened cache');
return cache.addAll(cachelist);
})
);
// 通常注册之后,激活须要等到再次刷新页面后再激活
// 可防止出现等待的状况,这意味着服务工做线程在安装完后当即激活
self.skipWaiting();
})
self.addEventListener('activate', function (event) {
// 若缓存数据更改,则在这里更新缓存
var cacheDeletePromise = caches.keys()
.then(keyList => {
Promise.all(keyList.map(key => {
if (key !== CACHE_NAME) {
var deletePromise = caches.delete(key)
return deletePromise
} else {
Promise.resolve()
}
}));
});
event.waitUntil(
Promise.all([cacheDeletePromise]).then(res => {
this.clients.claim()
})
);
})
复制代码
用于处理更新缓存,新的文件。到如今咱们仍是没有用到serviceWorker
的缓存,下面重头戏来了缓存和返回请求。
上咱们已经安装而且激活了SW,如今咱们要返回一个缓存的响应。SW用户转至其余页面或刷新当前页面后,将开始接受fetch
事件。
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request)
.then(function(response) {
// Cache hit - return response
if (response) {
return response;
}
return fetch(event.request);
})
);
});
复制代码
在定义的fetch
事件中,咱们在event.respondWith()
中传入来自caches.match()
的一个promise
。caches.match()
这个方法检视该请求,并从服务工做线程所建立的任何缓存中查找缓存的结果。若是命中返回缓存值,不然,将调用fetch
以发出网络请求。运行效果以下:
若是咱们想把新的请求也缓存掉,修改代码以下:
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request)
.then(function(response) {
// Cache hit - return response
if (response) {
return response;
}
// return fetch(event.request);
var requestClone = event.request.clone();
return fetch(requestClone).then(response => {
if(!response || response.status !== 200 || response.type !== 'basic') {
return response;
}
var responseToCache = response.clone();
caches.open(CACHE_NAME)
.then(function(cache) {
cache.put(event.request, responseToCache);
});
return response;
});
})
);
});
复制代码
执行操做以下:
fetch
请求中添加对 .then()
的回调。没有缓存新请求时效果以下:
当使用咱们下面的代码时,效果图以下:
即便异步请求的png
图片也被加入了缓存中。
在如下状况下会触发更新:
push
和 sync
等功能事件,除非在前 24 小时内已进行更新检查。.register()
,仅在 SW
网址已发生变化时。当触发更新时,会通过大体以下步骤:
JavaScript
文件。 用户导航至您的站点时,浏览器会尝试在后台从新下载定义 SW
的脚本文件。 若是 SW
文件与其当前所用文件存在字节差别,则将其视为新 SW
。SW
与现有 SW
一块儿启动,并获取本身的 install
事件。SW
仍控制着当前页面,所以新 SW
将进入 waiting
状态。新 Worker
出现不正常状态代码(例如,404)、解析失败,在执行中引起错误或在安装期间被拒,则系统将舍弃新 Worker
,但当前 Worker 仍处于活动状态
。更新的 Worker 将 wait
,直到现有 Worker
控制零个客户端。(注意,在刷新期间客户端会重叠。)self.skipWaiting()
可防止出现等待状况,这意味着 Service Worker
在安装完后当即激活。更新一个叫作sw_cache_v2
的新的SW
缓存,代码以下:
const CACHE_NAME = 'sw_cache_v2';
self.addEventListener('install', (event) => {
event.waitUntil(
// cacheStorage API 可直接用caches来替代
// open方法建立/打开缓存空间,并会返回promise实例
// then来接收返回的cache对象索引
caches.open(CACHE_NAME)
// cache对象addAll方法解析(同fetch)并缓存全部的文件
.then(function(cache) {
return cache.add('index_copy.png')
})
);
// 通常注册之后,激活须要等到再次刷新页面后再激活
// 可防止出现等待的状况,这意味着服务工做线程在安装完后当即激活
self.skipWaiting();
})
self.addEventListener('activate', function (event) {
// 若缓存数据更改,则在这里更新缓存
var cacheDeletePromise = caches.keys()
.then(keyList => {
Promise.all(keyList.map(key => {
if (key !== CACHE_NAME) {
var deletePromise = caches.delete(key)
return deletePromise
} else {
Promise.resolve()
}
}));
});
event.waitUntil(
Promise.all([cacheDeletePromise]).then(res => {
this.clients.claim()
})
);
});
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request)
.then(function(response) {
// Cache hit - return response
if (response) {
return response;
}
return fetch(event.request);
}
)
);
});
复制代码
代码执行效果以下图所示:
整个过程咱们大体通过了install => waiting => activate
三个过程。
咱们在代码中把sw_cache_v1
更改成sw_cache_v2
,咱们从新Install
了一个新的缓存sw_cache_v2
,而且经过添加了一个缓存进去cache.add('index_copy.png')
。
若是新的缓存安装成功SW
后,更新的SW
将延迟激活,直到现有SW
再也不控制任何客户端。此状态为waiting
,这是浏览器确保每次只运行一个SW
版本的样式。
旧 SW
退出时将触发 Activate
,新 SW
将可以控制客户端。此时,您能够执行在仍使用旧 Worker
时没法执行的操做,如迁移数据库和清除缓存。 在上面的演示中,我维护了一个指望保存的缓存列表,而且在 activate
事件中,我删除了全部其余缓存,从而也移除了旧的 sw_cache_v1
缓存。
不要更新之前的版本。它多是许多旧版本的
SW
。
若是您将一个 promise
传递到 event.waitUntil()
,它将缓冲功能事件(fetch、push、sync
等),直到 promise
进行解析。所以,当您的 fetch
事件触发时,激活已所有完成。
Cache storage API
属于“源存储”(如localStorage
和IndexedDB
)。若是您在同源上运行许多网站(例如,yourname.github.io/myapp
),请注意,不要删除其余网站的缓存。为避免此问题,能够为您的缓存名称提供一个在当前网站上具备惟一性的前缀(例如,myapp-static-v1),而且不要删除缓存,除非它们以 myapp- 开头。
等待阶段表示您每次只能运行一个网站版本,但若是您不须要该功能,您能够经过调用 self.skipWaiting()
尽快将新 SW
激活。 这会致使您的 SW
将当前活动的 Worker
逐出,并在进入等待阶段时尽快激活本身(或当即激活,前提是已经处于等待阶段)。这不能让您的 Worker
跳过安装,只是跳过等待阶段。 skipWaiting()
在等待期间调用仍是在以前调用并无什么不一样。通常状况下是在 install
事件中调用它:
self.addEventListener('install', event => {
self.skipWaiting();
event.waitUntil(
// caching etc
);
});
复制代码
与 clients.claim()
同样,它是一个竞态。
skipWaiting()
意味着新 Service Worker 可能会控制使用较旧Worker
加载的页面。这意味着页面提取的部分数据将由旧 Service Worker 处理,而新 Service Worker 处理后来提取的数据。若是这会致使问题,则不要使用skipWaiting()
。
当页面刷新或者执行功能性事件时,浏览器会自动检查更新,其实咱们也能够手动的来触发更新:
navigator.serviceWorker.register("/sw.js").then(reg => {
// sometime later…
reg.update();
});
复制代码
若是你但愿你的用户访问页面很长时间并且不用刷新,那么你能够每一个一段时间调用一次update()
。
你可能会考虑给每一个 SW
不一样的 URL
。**千万不要这么作!**在 SW
中这么作是“最差实践”,要在原地址上修改 SW
。
举个例子来讲明为何:
index.html
注册了sw-v1.js
做为SW
。
sw-v1.js
对index.html
作了缓存,也就是缓存优先(offline-first
)。
你更新了index.html
从新注册了在新地址的 SW sw-v2.js
.
若是你像上面那么作,用户永远也拿不到sw-v2.js
,由于index.html
在sw-v1.js
缓存中,这样的话,若是你想更新为sw-v2.js
,还须要更改原来的sw-v1.js
。
这里主要分为:
SW
生命周期是专为用户构建的,这就给开发工做带来必定的困难。幸运的是,咱们可经过如下几个工具解决这个问题:
这可以使生命周期变得对开发者友好。每次浏览时都将:
SW
。install
事件并更新缓存。SW
。若是您有一个 Worker
在等待,您能够按 DevTools
中的“skip waiting
”以当即将其提高到“active
”。同时也能够经过self.skipWaiting()
来实现。
若是您强制从新加载页面 (shift-reload)
,则将彻底绕过 SW
。页面将变得不受控制。此功能已列入规范,所以,它在其余支持 SW
的浏览器中也适用。
为支持尽量多的模式,整个更新周期都是可观察的:
navigator.serviceWorker.register('/sw.js').then(reg => {
reg.installing; // the installing worker, or undefined
reg.waiting; // the waiting worker, or undefined
reg.active; // the active worker, or undefined
reg.addEventListener('updatefound', () => {
// A wild service worker has appeared in reg.installing!
const newWorker = reg.installing;
newWorker.state;
// "installing" - the install event has fired, but not yet complete
// "installed" - install complete
// "activating" - the activate event has fired, but not yet complete
// "activated" - fully active
// "redundant" - discarded. Either failed install, or it's been
// replaced by a newer version
newWorker.addEventListener('statechange', () => {
// newWorker.state has changed
});
});
});
navigator.serviceWorker.addEventListener('controllerchange', () => {
// This fires when the service worker controlling this page
// changes, eg a new worker has skipped waiting and become
// the new active worker.
});
复制代码
Sync事件
让你能够先将网络相关任务延迟到用户有网络的时候再执行。这个功能常被称做“背景同步”。这功能能够用于保证任何用户在离线的时候所产生对于网络有依赖的操做,最终能够在网络再次可用的时候抵达它们的目标。
代码示例以下
navigator.serviceWorker.ready.then(registration => {
document.getElementById('submit').addEventListener('click', () => {
registration.sync.register('submit').then(() => {
console.log('sync registered!');
});
});
});
复制代码
咱们指定在一个按钮的点击事件里,在一个全局的 ServiceWorkerRegistration
对象身上调用 sync.register
。
简单地讲,任何你须要确保在有网络时马上执行或者等到有网再执行的操做,都须要注册为一个sync事件
。
这操做能够是发送一个评论,或者获取用户信息,在SW的事件监听器里会以下定义:
// sw.js
self.addEventListener('sync', event => {
if (event.tag === 'submit') {
console.log('sync!');
}
});
复制代码
咱们监听一个 sync 事件
,而后在 SyncEvent
对象上检查 tag
是否匹配咱们在点击事件里所设定的 'submit'
。
若是多个 tag
标记为 submit
的 sync
事件被注册了,sync
事件处理器只会运行一次。
因此在这个例子里,若是用户离线了,而后点击按钮7次,当网络再次连上,全部的sync
注册都会合而为一,sync
事件只会触发一次。
若是用户的网络时联通的,那么sync事件
会马上触发而且马上执行你所定义的任务。
而若是用户离线了,sync 事件
会在网络恢复后第一时间触发。
对于在install
中发现没有缓存,页面又依赖但又不常常变化的资源,能够在页面打开或发生用户交互时触发fetch
而后使用fetch api
再去网络拉取,将返回正常的response缓存
起来以便下次使用。
progressive-cache
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request)
.then(function(response) {
// Cache hit - return response
if (response) {
return response;
}
// return fetch(event.request);
var requestClone = event.request.clone();
return fetch(requestClone).then(response => {
if(!response || response.status !== 200 || response.type !== 'basic') {
return response;
}
var responseToCache = response.clone();
caches.open(CACHE_NAME)
.then(function(cache) {
cache.put(event.request, responseToCache);
});
return response;
});
})
);
});
复制代码
在fetch事件
中,仅去匹配资源,若匹配失败,表现出来的就是前端页面对于该 资源加载失败。这里容错性比较差,适用于页面资源都是静态资源的,且不能使用不影响安装的资源预缓存。
cache-only
// SW请求拦截事件
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.open(OFFLINE_CACHE_NAME).then((cache) => {
// 匹配资源若是命中返回缓存
return cache.macth(event.request.url);
});
);
});
复制代码
在fetch事件
中,仅将request
从新抽出用fetch
去网络加载并返回给前端页面。适用于资源大可能是动态资源、实时性要求高的场景。
network-only
// SW请求拦截事件
self.addEventListener('fetch', (event) => {
// 仅使用网络加载
event.respondWith(fetch(event.request));
});
复制代码
简单的资源缓存中使用的就是缓存优先策略,先去缓存匹配,匹配失败折回网络,这算是最经常使用、容错性能好的一种策略。
firstCache
function firstCache (cacheName, request) {
// 打开SW
return caches.open(cacheName).then(cache => {
// 匹配请求路径
return cache.match(request).then(response => {
// fetch请求
var fetchServer = function() {
return fetch(request).then(newResponse => {
cache.put(request, newResponse.clone());
return newResponse;
});
}
// 若是缓存中有数据则返回,不然请求网络数据
if (response) {
return response;
} else {
return fetchServer();
}
});
});
}
复制代码
在fetch事件
中先去网络fetch
,当出现服务器故障或者网络不良时,折回本地缓存,目的是为了展现最新的数据,对实时性要求比较高但又可以带来良好体验的应用,好比天气类型应用。
firstNet
function firstNet(cacheName, request) {
// 请求网络数据并缓存
return fetch(request).then(response => {
// 响应clone
var responseCopy = response.clone();
caches.open(cacheName).then(cache => {
// fetch请求
cache.put(request, responseCopy);
});
return response;
}).catch(() => {
// fetch失败走本地缓存
return caches.open(cacheName).then(cache => {
return cache.match(request);
});
});
}
复制代码
在fetch事件
中同时发起本地缓存匹配及网络请求,谁先返回使用谁的,该方案适用于对性能要求比较高的站点,缩短了缓存优先策略中有可能缓存中没有资源再折回网络的时间消耗。
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));
}
// ...
})
复制代码
Push消息
在SW
里,经过 push 事件
以及浏览器的 Push API
,能够实现push消息
的功能。 在说道web push消息
的时候,其实涉及到两个正在完善中的技术:消息提醒
与 信息推送
。
用SW
实现消息提醒挺简单直接:
// app.js
// ask for permission
Notification.requestPermission(permission => {
console.log('permission:', permission);
});
// display notification
function displayNotification() {
if (Notification.permission == 'granted') {
navigator.serviceWorker.getRegistration()
.then(registration => {
registration.showNotification('this is a notification!');
});
}
}
复制代码
// sw.js
self.addEventListener('notificationclick', event => {
// 消息提醒被点击的事件
});
self.addEventListener('notificationclose', event => {
// 消息提醒被关闭的事件
});
复制代码
你须要先向用户寻求让你的网页产生消息提醒的权限。以后,你就能够弹出提示信息,而后处理某些事件,好比用户把消息关掉的事件。
信息推送涉及到利用浏览器提供的Push API
以及后端的配合实现。要讲解如何使用Push API
彻底能够再写一篇文章,不过基本的套路以下:
这是个略微复杂难懂的过程,已经超出这篇文章的讨论范围。
什么是 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.
其大概意思是它对常见的 SW
操做进行了一层封装, 根据最佳实践方便了开发者的使用。所以在咱们快速开发本身的 PWA
应用时使用 Workbox
是最合适不过的了。
它主要有如下几大功能 :
直接修改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()...
复制代码
若是浏览器支持,能够直接引用API接口:
precaching
能够在注册成功后直接缓存的文件;routing
匹配符合规则的url
与strategies
合做来完成文件的缓存。代码以下:
// 注册完成后,即缓存对应的文件列表
workbox.precaching.precacheAndRoute([
'/src/static/js/index.js',
'/src/static/css/index/css'
])
// routing方法匹配请求文件路径,strategies用来存储对应文件
workbox.routing.registerRoute(
matchFunction, // 字符串或者是正则表达式
handler // 可使用workbox.strategies缓存策略来缓存
)
复制代码
workbox.strategies
缓存策略有:
staleWhileRevalidate
使用已有的缓存,而后发起请求,用请求结果来更新缓存;networkFirst
先发起请求,请求成功后会缓存结果。若是失败,则使用最新的缓存;cacheFirst
老是先使用缓存,若是无匹配的缓存,则发起网络请求并缓存结果;networkOnly
强制发起请求;cacheOnly
强制使用缓存。官方也有给了实现逻辑以下。
只从缓存中读取,当缓存中没有数据时,读取失败。
只经过网络请求进行资源请求,若请求失败,则返回失败响应。
不难看出,这种策略是为了保证在第一次请求成功以后,后面屡次的请求始终都能返回结果。
workbox.routing.registerRoute(/\.(js|css)$/,
workbox.strategies.networkFirst({
// 给网络请求0.5秒,若仍未返回则从缓存中取数据
networkTimetoutSeconds: 0.5,
cacheName: 'css.js',
}),
);
复制代码
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',
}),
);
复制代码
在本篇文章中详细的记录了有关SW
的主要功能和能给咱们带来的好处。通常在开发中仍是推荐使用workbox
,最后若是我的有兴趣的能够本身编写示例来验证文章中的代码示例。
SW主要做用
SW几种策略
感受写的不错请点一下赞,据说长的帅的人都会点赞,而且点赞后走上人生巅峰。