浅谈 Service Worker 在缓存资源以及Web Push上的应用
作者:互联网
一、 service worker 是什么
一句话概括
一个服务器与浏览器之间的中间人角色,如果网站中注册了service worker
那么它可以拦截当前网站所有的请求,进行判断(需要编写相应的判断程序),如果需要向服务器发起请求的就转给服务器,如果可以直接使用缓存的就直接返回缓存不再转给服务器。从而大大提高浏览体验。
细碎的描述
- 基于
web worker
(一个独立于JavaScript主线程的独立线程,在里面执行需要消耗大量资源的操作不会堵塞主线程) - 在
web worker
的基础上增加了离线缓存的能力 - 本质上充当
Web
应用程序(服务器)与浏览器之间的代理服务器(可以拦截全站的请求,并作出相应的动作->由开发者指定的动作) - 创建有效的离线体验(将一些不常更新的内容缓存在浏览器,提高访问体验)
- 由事件驱动的,具有生命周期
- 可以访问
cache
和indexDB
- 支持推送
- 并且可以让开发者自己控制管理缓存的内容以及版本
本篇文章主要在缓存和推送上对ServiceWorker进行分析。
二、 使用Service Worker 缓存资源
注册Service worker 在你的index-service-worker.html加入以下内容
/* 判断当前浏览器是否支持serviceWorker */
if ('serviceWorker' in navigator) {
/* 当页面加载完成就创建一个serviceWorker */
window.addEventListener('load', function () {
/* 创建并指定对应的执行内容 */
/* scope 参数是可选的,可以用来指定你想让 service worker 控制的内容的子目录。 在这个例子里,我们指定了 '/',表示 根网域下的所有内容。这也是默认值。 */
navigator.serviceWorker.register('./serviceWorker.js', {scope: './'})
.then(function (registration) {
console.log('ServiceWorker registration successful with scope: ', registration.scope);
})
.catch(function (err) {
console.log('ServiceWorker registration failed: ', err);
});
});
}
安装worker:在我们指定的处理程序serviceWorker.js中书写对应的安装及拦截逻辑
/* 监听安装事件,install 事件一般是被用来设置你的浏览器的离线缓存逻辑 */
this.addEventListener('install', function (event) {
console.log('worker installed')
/* 通过这个方法可以防止缓存未完成,就关闭serviceWorker */
event.waitUntil(
/* 创建一个名叫V1的缓存版本 */
caches.open('v1').then(function (cache) {
/* 指定要缓存的内容,地址为相对于跟域名的访问路径 */
return cache.addAll([
'./index-service-worker.html'
]);
})
);
/* 注册fetch事件,拦截全站的请求 */
this.addEventListener('fetch', function(event) {
event.respondWith(
// magic goes here
/* 在缓存中匹配对应请求资源直接返回 */
caches.match(event.request)
);
});
});
部署测试:
html页面必须部署在服务器上运行,所以建议使用iis
本地搭建一个服务器。具体步骤不在详述,自行百度即可。运行效果如下:
然后打开 谷歌浏览器 application
栏,可以找到serviceWorker
已经被成功加载
serviceWorker
一旦被加载,如果serviceWorker
文件没有变化,则不会再次被安装,会像localstorage一样缓存在网站中。手动卸载serviceWorker
可以点击Unregister
,这样再次刷新页面,serviceWorker
会被重新加载。
接下来我们添加一张网页图片,注意,这时候我是用iis
新建了一个网站 8002
端口。在8001
网站加载这个图片,并且把这个图片添加到ServiceWorker.js
的缓存目录中:
/* 监听安装事件,install 事件一般是被用来设置你的浏览器的离线缓存逻辑 */
this.addEventListener('install', function (event) {
console.log('worker installed')
/* 通过这个方法可以防止缓存未完成,就关闭serviceWorker */
event.waitUntil(
/* 创建一个名叫V1的缓存版本 */
caches.open('v1').then(function (cache) {
/* 指定要缓存的内容,地址为相对于跟域名的访问路径 */
return cache.addAll([
'./index-service-worker.html',
'http://localhost:8002/testimage.png'
]);
})
);
});
这里我们为了试验效果,排除浏览器本身缓存(disk cache
和 memory cache
)的影响,先禁用浏览器缓存:
我们部署完毕图片之后,刷新页面,看到由于我们修改了ServiceWorker
文件内容,浏览器重新加载了我们的ServiceWorker:
刷新页面,查看testimage.png和的加载方式,发现是来自ServiceWorker:
这时我们断开8002
端口的服务器:发现图片仍然可以正常显示:
三、使用Service Worker 推送服务器消息
用Service Worker
发送Push(Notification
)或者叫web push
。Web push
在国外的网站很流行,但在国内几乎没见到,主要还是因为谷歌在境内无法访问,因为web push
走的是谷歌FCM通道,需要能接收到谷歌服务器的消息。但正常网络环境下是无法访问谷歌的,如果需要正常访问需要对应的服务端服务器运行在可以访问到谷歌的网络服务器上。
这里由于应用范围不广,服务器端的推送流程我们就不说了,也不好模拟。客户端调试器中有推送消息的测试接口,我们正好可以拿来测试。
客户端添加监听
this.addEventListener('push', function (event) {
console.log('[Service Worker] Push Received.');
console.log(event.data)
console.log(`[Service Worker] Push had this data: "${event.data.text()}"`);
event.waitUntil(self.registration.showNotification('提示信息test', {
body: event.data.text(),
icon: './images/logo/logo152.png',
}));
event.data.text()
});
打开F12 Application 找到我们的Worker,发送推送消息
首先控制台报了一个错:
很明显,浏览器推送需要用户授权才可以。这个跟目前的主流手机操作系统保持一致,避免频繁的弹窗,我们需要在用户注册完WebWorker之后,申请用户的授权:
if ('serviceWorker' in navigator) {
/* 当页面加载完成就创建一个serviceWorker */
window.addEventListener('load', function () {
/* 创建并指定对应的执行内容 */
/* scope 参数是可选的,可以用来指定你想让 service worker 控制的内容的子目录。 在这个例子里,我们指定了 '/',表示 根网域下的所有内容。这也是默认值。 */
navigator.serviceWorker.register('./serviceWorker.js', { scope: './' })
.then(function (registration) {
if (window.PushManager) {
registration.pushManager.getSubscription().then(subscription => {
// 如果用户没有订阅
if (!subscription) {
subscribeUser(registration);
} else {
console.log("You have subscribed our notification");
}
});
}
console.log('ServiceWorker registration successful with scope: ', registration.scope);
})
.catch(function (err) {
console.log('ServiceWorker registration failed: ', err);
});
});
}
subscribeUser 方法如下:
function subscribeUser(swRegistration) {
const applicationServerPublicKey = "BBlY_5OeDkp2zl_Hx9jFxymKyK4kQKZdzoCoe0L5RqpiV2eK0t4zx-d3JPHlISZ0P1nQdSZsxuA5SRlDB0MZWLw";
const applicationServerKey = base64ToUint8Array(applicationServerPublicKey);
swRegistration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: applicationServerKey
})
// 用户同意
.then(function(subscription) {
console.log('User is subscribed:', JSON.stringify(subscription));
//--向服务器注册当前订阅
})
// 用户不同意或者生成失败
.catch(function(err) {
console.log('Failed to subscribe the user: ', err);
});
}
完成之后,刷新页面,出现如下提示。点击允许。
我们再次尝试用控制台推送:果然出现了如下提示信息。
以上过程只是用最简单的方式实现了客户端推送,生成公钥和私钥的过程都进行了忽略,且省略了服务器部分对这里的处理。有关服务器部分的订阅以及推送逻辑,可以参考这篇文章
四、结语
Service Worker
让我们在Web端也能有像原生APP一样的Push
通知,使得Web端越来越像原生APP端,随着HTML5的其它新功能如WebAssembly
提高运行速度,WebWorker
多线程支持,数据库支持大量数据的管理和支持,Websocket
进行实时通信,WebRTC
进行P2P多媒体传输,还有WebGL
、新进的WebVR
等,使得在浏览器端能够做的事情越来越多,体验越来越丰富,而且这种Web APP
还是跨平台的。Web
技术日新月异的发展,让我们相信Web有搞头。
标签:function,Web,缓存,console,浅谈,Service,worker,serviceWorker,event 来源: https://blog.csdn.net/qq_29722281/article/details/111873764