网站首页 > 技术文章 正文
本文已经原作者 Felix Gerschau 授权翻译
service worker 是什么
Service Worker 是 Chrome 团队提出和力推的一个 WEB API,用于给 web 应用提供高级的可持续的后台处理能力。该 WEB API 标准起草于 2013 年,于 2014 年纳入 W3C WEB 标准草案,当前还在草案阶段。
Service Worker 最主要的特点是:在页面中注册并安装成功后,运行于浏览器后台,不受页面刷新的影响,可以监听和截拦作用域范围内所有页面的 HTTP 请求。
类似一个服务器与浏览器之间的中间人角色,如果网站中注册了service worker 那么它可以拦截当前网站所有的请求,进行判断(需要编写相应的判断程序),如果需要向服务器发起请求的就转给服务器,如果可以直接使用缓存的就直接返回缓存不再转给服务器。从而大大提高浏览体验。
Service Worker 可以启用以前原生应用程序专有的一组功能。Service Worker 的初稿已于2014年发布,现在所有主流浏览器都支持它们。
就像已经指出的定义一样,Service Worker 是网络代理。这意味着它们可以控制页面中的所有网络请求,并且可以对其进行编程,使用缓存的进行响应。
Service Worker 特点
- 网站必须使用 HTTPS。除了使用本地开发环境调试时(如域名使用 localhost)
- 运行于浏览器后台,可以控制打开的作用域范围下所有的页面请求
- 单独的作用域范围,单独的运行环境和执行线程
- 不能操作页面 DOM。但可以通过事件机制来处理
如何注册 Service Worker
注册 Service Worker 不需要太多代码,只需要一个用于Service Worker 代码的 JS 文件,一般取名为 service-worker.js
// 首先检查浏览器是否支持 Service Worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker
.register('/sw/service-worker.js')
.then(function(registration) {
console.log(registration);
})
.catch(function(err) {
console.log(err);
});
}
其实关键代码只有一行:
navigator.serviceWorker.register('/sw/service-worker.js')
注意:
Service Worker 的注册路径决定了其 scope 默认作用范围。示例中 service-worker.js是在 /sw 路径下,这使得该 Service Worker 默认只会收到 /sw 路径下的 fetch事件。如果存放在网站的根路径下,则将会收到该网站的所有 fetcg事件。
如果希望改变它的作用域,可在第二个参数设置 scope范围。示例中将其改为了根目录,即对整个站点生效。
另外应意识到这一点:Service Worker 没有页面作用域的概念,作用域范围内的所有页面请求都会被当前激活的 Service Worker 所监控。
Service Worker 可以启用哪些功能?
在本节中,我将进一步详细介绍Service Worker的功能,包括一些小代码示例。
服务工作者启用以下功能,这些功能也是 PWA的核心:
- 离线功能
- 定期后台同步
- 推送通知
离线功能
Service Worke 通过缓存资源和拦截网络请求来提供离线功能,这些请求可以与先前缓存的资源一起使用,而不是重新请求服务器。
我们可以从中得出两个步骤:
- 预缓存
- 从缓存中处理请求
这两个步骤都利用了Cache API,它由 Web Workers 和浏览器使用,并且为我们提供了用于网络请求的存储机制。
对 Web 和服务工作人员上下文的 localStorage 访问被阻止,以防止并发性问题。作为一种替代方案,IndexedDB 可以用于存储大量数据。
预缓存
预缓存是一个术语,描述了在 Service Worker 处于激活状态之前下载和缓存文件。它是在 Service Worker 生命周期的“install ”步骤中完成的。一旦 Service Worker 处于激活状态,它将准备为缓存中的文件提供服务。
通常,我们要缓存 Application Shell,这是运行网站所需的最少代码量。如果开发了本机应用程序,那么这就是您将上传到应用程序商店的代码包。这包括所有必需的基本JavaScript,HTML和图片。
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open(currentCache.offline).then(function(cache) {
return cache.addAll([
'/static/images/offline.svg',
'/static/html/offline.html',
]);
});
);
});
从缓存中处理请求
在此阶段,我们已经将所有应用程序代码存储在缓存中,并且Service Worker 已处于激活即运行于浏览器后台。
现在唯一缺少的是监听 fetch 事件并从缓存中返回结果。可以通过 fetch 事件可以拦截到当前作用域范围内的 http/https 请求,并且给出自己的响应。结合 Fetch API ,可以简单方便地处理请求响应,实现对网络请求的控制。
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request).then(function(response) {
return response || fetch(event.request);
})
);
});
在本例中,我们尽可能使用缓存的内容进行响应。作为回退,我们发出一个网络请求。
这里实现了一个缓存优先、降级处理的策略逻辑:监控所有 http 请求,当请求资源已经在缓存里了,直接返回缓存里的内容;否则使用 fetch API 继续请求,如果是 图片或 css、js 资源,请求成功后将他们加入缓存中;如果是离线状态或请求出错,则降级返回预缓存的离线内容。
定期后台同步
正如在引言中已经提到的那样,Service Worker 与其他服务工作者在一个单独的线程上运行,所以即使关闭页面,它们也可以执行其代码。此功能对于执行后台同步和提供推送通知很重要。
后台同步
用户离开页面后,后台同步通常用于同步数据。
例如,在手机上编辑文档后,我们写完会点击“保存”并离开页面。如果在编辑文档期间连接断开,我们必须等待连接恢复才能保存文档。
后台同步的目的是解决这个问题,一旦连接重新建立,自动发送数据。
来看一个示例:
app.js
navigator.serviceWorker.ready.then((registration) => {
return registration.sync.register('sync-save-document');
});
service-worker.js
self.addEventListener('sync', (event) => {
if (event.tag === 'sync-save-document') {
event.waitUntil(saveDocument());
}
});
saveDocument是一个返回 Promise,如果被拒绝(例如由于网络问题),同步将自动重试。
要注意的一件事是,同步标记必须是唯一的。例如,如果我要安排5个“message”类型的后台同步,则只有最后一个会通过。因此,在这种情况下,每个标签都应具有唯一的标识符。
定期后台同步
定期后台同步解决与正常后台同步不同的问题。该API可用于在后台更新数据,而不必等待用户。
这对很多应用程序都很有用。有了这项技术,用户可以在没有互联网连接的情况下阅读最新的新闻文章。
为了防止滥用这一功能,同步的频率取决于浏览器为每个网站设置的站点参与度分数。如果你经常打开一个网页应用,这个频率最多可以达到12个小时。
要实现此目的一个要求是,该网站已作为移动设备上的 PWA 安装并添加到主屏幕。
推送通知
Service Worker另一个类似本机的特性是推送通知。我们通常通过手机短信或社交媒体通知的形式知道它们,但它们也可以在台式电脑上使用。
除Safari之外,所有主流浏览器都支持它们,而Safari对桌面应用程序有自己的实现。
要使用推送通知,需要设置一台服务器,该服务器会将通知推送给所有客户端。由于Service Worker在后台在另一个线程上运行,因此即使页面当前未打开,用户也可以看到推送通知。
推送的实现有两步:
不同浏览器需要用不同的推送消息服务器。以 Chrome 上使用 Google Cloud Messaging<GCM> 作为推送服务为例,第一步是注册 applicationServerKey(通过 GCM 注册获取),并在页面上进行订阅或发起订阅。每一个会话会有一个独立的端点(endpoint),订阅对象的属性(PushSubscription.endpoint) 即为端点值。将端点发送给服务器后,服务器用这一值来发送消息给会话的激活的 Service Worker (通过 GCM 与浏览器客户端沟通)。
浏览器支持情况
除了 Safari 和 IE/Edge,大部分现代浏览器都已经得到了支持。
总结
希望通过本文介绍基本概念和特性,可以让你更好地理解Service Worker。
作者:Felix Gerschau 译者:前端小智 来源:Felix Gerschau 原文:https://felixgerschau.com/service-workers-explained-introduction-javascript-api/
猜你喜欢
- 2024-10-24 web性能优化的15条实用技巧(web应用性能优化思路)
- 2024-10-24 如何在 Service Worker 重新启动时重用信息
- 2024-10-24 Python在selenium里面注入JavaScript程序的方法
- 2024-10-24 requireJS 实战(requirejs define)
- 2024-10-24 面试妥了!2020 爬虫面试题目合集(爬虫面试经历)
- 2024-10-24 Nest.js 从零到壹系列(一):项目创建&路由设置&模块
- 2024-10-24 JS小知识,分享 7 个高频的工具函数,也许你用的上
- 2024-10-24 如何使用Playwright优化测试性能(play—player)
- 2024-10-24 JavaScript开发人员都应知道的异步迭代,你会了吗?
- 2024-10-24 WebSocket能干些啥?(websocket作用)
- 11-26Win7\8\10下一条cmd命令可查得笔记本电脑连接过的Wifi密码
- 11-26一文搞懂MySQL行锁、表锁、间隙锁详解
- 11-26电脑的wifi密码忘记了?一招教你如何找回密码,简单明了,快收藏
- 11-26代码解决忘记密码问题 教你用CMD命令查看所有连接过的WIFI密码
- 11-26CMD命令提示符能干嘛?这些功能你都知道吗?
- 11-26性能测试之慢sql分析
- 11-26论渗透信息收集的重要性
- 11-26如何查看电脑连接过的所有WiFi密码
- 最近发表
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)