ServiceWorker 是 PWA 技术栈中的一个重要成员,它是一个用于使Web 应用在离线状态下依然可以工作,且具有网络拦截的浏览器功能。这个功能由一段运行在浏览器后台线程的 JavaScript 代码来实现。
一、ServiceWorker的作用
ServiceWorker 的主要功能是使得 Web 应用程序可以离线运行。通过 ServiceWorker 可以缓存 Web 应用在用户设备上的一些文件,如HTML、JS、CSS、图片等,这样即使用户离线,也能通过ServiceWorker的缓存功能加载并渲染对应的 Web 应用页面。
另外,ServiceWorker 还能够通过网络拦截功能对接口的请求做一些处理,这可以用于 Offline First 等场景的开发。例如当Web 应用在用户设备上没有网络或者网络差的情况下,ServiceWorker 可以使用它的缓存功能提供一些基础信息或者降级处理。当然,ServiceWorker 的功能不止这些,还可以配合 Push Notification 等技术进行 Web 应用的推送、更新等操作。
二、ServiceWorker无效的原因
ServiceWorker 运行的环境比较独特,它没有 window 或 document 的对象,也没有 localStorage 或者 indexedDB 之类的浏览器 API。这样导致ServiceWorker中某些操作是不能进行的。
另外,由于 ServiceWorker 运行在后台线程之中,所以为了确保不会出现异常情况,ServiceWorker 只能响应HTTPS或者本地环境,这也是 ServiceWorker 无法应用到经典的 HTTP 协议中的一个原因。
三、阮一峰关于ServiceWorker的看法
阮一峰在他的博客中提到过 ServiceWorker:“ServiceWorker 与 Web Worker 非常相似,都是运行在浏览器后台的 JavaScript 线程。ServiceWorker 和传统浏览器 js 不同,它可以脱离标签页运行,具有比较高的独立性,因此可以进行一些操作,比如缓存、推送等。”
在他的看来,ServiceWorker是一种比较快捷、简便的技术,可以极大地提升Web应用的易用性和性能体验。
四、ServiceWorker拦截请求
ServiceWorker 提供了一个对请求的拦截功能,在 ServiceWorker 中可以通过拦截特定类型的请求,例如接口请求或者资源请求,从而完成一些特殊的处理。
self.addEventListener('fetch', (event) => {
if (event.request.url.includes('your-api-url.com')) {
event.respondWith(fetch(event.request).then((res) => {
return res.json().then((data) => {
return new Response(JSON.stringify(data));
});
}));
}
});
上述代码中,我们监听了 fetch 事件,如果检测到该请求地址包含是某个API地址,则会使用 ServiceWorker 拦截该请求,然后获取响应结果进行数据相关处理后返回。
五、ServiceWorkers是什么意思
ServiceWorkers是指一类服务工作线程。ServiceWorker 是一种比较新的 HTML5 技术,它们被设计成运行在浏览器后台线程。
ServiceWorker 不会和浏览器标签页之间产生显著的交互,这使得它们可以被用于离线应用程序、消息推送、后台数据同步和其他类似的任务。ServiceWorker 的 API 本质上就是 Web Worker API 的一种,但提供了更多的能力和一些不同的限制。
六、ServiceWorker和Web Worker
ServiceWorker 和 Web Worker 非常相似,它们都是后台线程,都不能访问 DOM,提供了新的 JavaScript Worker 类,是 HTML5 中新添加的一种运行在浏览器后台的线程。
在 ServiceWorker 和 Web Worker 中,JavaScript 代码是一个独立的线程,不会阻塞主线程,允许同时做多件事情。
七、苹果ServiceWorker
苹果公司已经支持ServiceWorker技术,苹果 Safari 浏览器在 2017 年 6 月份开始支持ServiceWorker 的注册和使用,这对 PWA 应用的普及有着极为重要的意义。
八、Service workers与负责可靠实时交付的网络应用程序
ServiceWorker 可以让慢速和不可靠的网络情况下的 Web 应用程序依然能够拥有较好的用户体验。通过 ServiceWorker 的事件监听功能,开发者可以在网络离线的情况下,选择香港或者本地缓存提供用户一些基础信息,避免 Web 应用程序传输许多陈旧和冗余的数据。
此外,Service Worker 还为开发者提供了对本地缓存的实时控制功能,可以根据具体情况灵活调整缓存策略,可以选择在页面初始化或者在网络上下文变化之后更新缓存。
九、Service Worker在浏览器的支持情况
目前支持ServiceWorker 的主流浏览器有:
- Chrome 45+
- Firefox 44+
- Opera 32+
- Edge 17+
- Safari 11.1+
Safari 目前仅支持 HTTPS 环境下的 ServiceWorker。
十、Service Workers的完整示例代码
const CACHE_NAME = 'my-site-cache-v1';
const URLS_TO_CACHE = [
'/',
'/styles/main.css',
'/scripts/main.js',
'/images/logo.png',
'/pages/offline.html'
];
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME)
.then((cache) => {
return cache.addAll(URLS_TO_CACHE);
})
);
});
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request)
.then((response) => {
if (response) {
return response;
}
return fetch(event.request);
})
.catch(() => {
return caches.match('/pages/offline.html');
})
);
});
self.addEventListener('activate', (event) => {
const cacheWhitelist = ['my-site-cache-v2'];
event.waitUntil(
caches.keys()
.then((cacheNames) => {
return Promise.all(
cacheNames.map((cacheName) => {
if (cacheWhitelist.indexOf(cacheName) === -1) {
return caches.delete(cacheName);
}
})
);
})
.then(() => {
return self.clients.claim();
})
);
});
上述代码就是一个 ServiceWorker 实现离线缓存的完整代码示例。它安装和激活之后就会缓存指定的内容,后面在网络不可达的情况下,会从缓存中读取相应资源。如果缓存不存在,会返回缺省的 offline.html 页面。