(function () {
if (navigator.serviceWorker) {
// 获取页面 DOM 元素
var msgIpt = document.getElementById('ipt'),
showArea = document.getElementById('show'),
sendBtn = document.getElementById('sendBtn');
navigator.serviceWorker.register('service-worker3.js');
navigator.serviceWorker.addEventListener('message', function (event) {
// 接受数据,并填充在 DOM 中
showArea.innerHTML = showArea.innerHTML + ('<li>' + event.data.message + '</li>');
});
sendBtn.addEventListener('click', function () {
// 绑定点击事件,点击后发送数据
navigator.serviceWorker.controller.postMessage(msgIpt.value);
msgIpt.value = '';
});
}
})();
3. 更新 Service Worker
每次用户导航至使用 Service Worker 的站点时,浏览器会尝试在后台重新下载该脚本文件。这时新的 Service Worker 将会在后台安装,并在第二次访问时获取控制权,为了不与新的 Service Worker 缓存的文件冲突,我们可以使用类似 caches.open('v2') 语句来创建新的缓存目录。
Service Worker 也可以在后台主动发送请求,优化用户体验,图片来源于《饿了么的 PWA 升级实践》。
5. Service Worker 支持的所有事件
五、销毁 Service Worker
浏览器决定是否销毁 Service Worker。在无痕浏览中,当页面关闭时相应的 Service Worker 会被销毁,因此尽量不要在代码中留存全局变量。可以访问 chrome://inspect/#service-workers和 chrome://serviceworker-internals/ 来检查 Service Worker 是否已经停用。
小结
困扰 Web 用户多年的难题——丢失网络连接,从 APPCache 到 Service Worker,解决办法一直在完善。Service Worker 开启的服务工作线程,对如何步入 Web 应用开发之旅,提供了很棒的切入角度。
那么,如何从本文开始,更好的学习 Service Worker?结合更多其它技术博客与 Service Worker 的 API 文档会更好。本文图片素材、写作思路多取源于此。
这次体验一种新的博客风格,我们长话短说,针针见“血”。
备马
在深入 Service Worker 之前,我们需要快速回顾如下基础。
诞生之初,JavaScript 是单线程的。
进程有私有的虚拟地址空间、代码、数据和其它系统资源,进程申请创建和使用的系统资源会随其终止而销毁。线程运行在进程之中,系统创建进程之后就开始启动执行进程的主线程,并随主线程的退出而终止。
JavaScript 作为浏览器脚本语言,为方便准确无误的操作 DOM,诞生之初便采用了单线程的方式。举个例子,若多线程同时分别删除和修改同一个 DOM,我们很难预知其执行结果。
但单线程中,必须通过异步和回调来优化耗时操作。
我们在网页上提交一个表单,并不希望在提交后页面卡顿,一直等待服务端返回的提交结果。这时我们需要能在单线程中发送异步请求,点击提交表单后可以先在页面进行其他操作。
Ajax 让我们可以向后端发送异步请求,同时不影响用户在界面中继续操作。当 Ajax 接收到服务端的响应之后,便通过回调函数执行之后的操作。一个典型的异步 Ajax 实战场景如下:
当我们的多个请求需要依赖于上一个请求的服务端响应时,回调函数中 Ajax 的层级逐步提高,可维护性极度下降,这就是回调地狱。
I Promise U that I`ll Marry U!!!
Promise 由 ES6 标准原生支持。正如题名,Promise 作出诺言,也要因此承担成功(fulfilled)或失败(rejected)的结果,以便解决回调地狱问题:
Promise 对象的生命周期如下图。
除了异步编程,我们还可以有 Web Worker。
通过异步编程,我们的页面可以边响应用户的下一步操作边等待服务端的回应,不再拥有阻塞感,但 JavaScript 的单线程问题并没有得到相应的解决。通过 HTML 5 标准支持的 Web Worker,我们可以为 JavaScript 创建运行在后台的额外线程,并被多个页面共享。
在一个简单的 Web Worker 实例中,main.js 和 task.js 的源码如下。
在 Chrome 浏览器里,以上代码必须运行在 Web 容器如 Apache 中。同时,WebKit 内核加载并执行 Worker 线程的流程如下图所示。
冲锋
Service Worker 基于 Web Worker 事件驱动。
Service Worker 同样可以在浏览器后台挂起新线程,来缓解 JavaScript 的单线程问题。并且,我们可以用 Service Worker 拦截网络请求进行本地缓存或请求转发,相当于充当服务端与浏览器、浏览器与 Web 应用程序之间的代理服务器。
Service Worker 带来了速度,极大的提高了用户体验。
Service Worker 大量使用 Promise 对象。
因为通常 Service Worker 会等待响应后继续,并根据响应返回一个成功或者失败的操作。Promise 非常适合这种场景。
零、Service Worker 的生命周期。
所谓生命周期,包括 Service Worker 的注册、安装、激活、控制和销毁时的全部过程。我们需要对 Service Worker 的生命周期有所了解。
一、注册 Service Worker。
当浏览器对 Service Worker 提供原生支持时,我们便可以在页面加载后注册指定的 JavaScript 文件,并运行在后台线程之中,以下代码是这一过程的实例。
这里通过 php 内置命令监听项目目录,便能看到 Service Worker 注册成功。同时,在 Chrome 浏览器里,可以访问
chrome://inspect/#service-workers
和chrome://serviceworker-internals/
来检查 Service Worker 是否已经启用。二、安装 Service Worker。
安装阶段,我们可以执行任何任务。这里我们逐步打开缓存、缓存文件和确认所有需要的资产是否缓存。
ServiceWorker.js
中的实例安装代码如下:这要求我们在与项目根目录下建立
main.js
和main.css
空文件。我们可以在 Chrome 开发者工具里的“Application”菜单的“Cache Storage”中看到相应的缓存。并且在图中的“Service Workers”选项卡中看到正在运行的 Service Workers。且从上面的代码可以看到,通过 Service Worker 对象加载的文件拥有全局变量 caches 等,并且 self 关键字指向这个对象本身。cache 使我们可以存储网络响应发来的资源,并且根据它们的请求来生成 key。这个 API 和浏览器的标准的缓存工作原理很相似,且会持久存在,直到我们释放主动空间——我们拥有全部的控制权。
三、激活 Service Worker。
当 Service Worker 安装成功后,便被激活,这时可实时控制作用域中的所有网站,进行缓存文件等操作。不过首次使用 Service Worker 的页面需要再次加载才会受其控制。
四、控制 Service Worker
以下列举几个常见的 Service Worker 应用场景。
1. 文件缓存
通过上述文件缓存过程,我们可以告诉 Service Worker 如何使用这些缓存文件,并通过 fetch 事件来捕获。fetch 事件只会在浏览器准备请求 Service Worker 控制的资源时才会被触发。这些资源包括了指定的 scope 内的文档,和这些文档内引用的其他任何资源。
2. 多页面传递消息
我们可以打开多个 https://nzv3tos3n.qnssl.com/message/msg-demo.html 测试页面来进行测试,效果如下。
其中,
index.js
源码为:3. 更新 Service Worker
每次用户导航至使用 Service Worker 的站点时,浏览器会尝试在后台重新下载该脚本文件。这时新的 Service Worker 将会在后台安装,并在第二次访问时获取控制权,为了不与新的 Service Worker 缓存的文件冲突,我们可以使用类似
caches.open('v2')
语句来创建新的缓存目录。当新的 Service Worker 激活,记得删除 v1 缓存目录,代码如下。
4. 预缓存
Service Worker 也可以在后台主动发送请求,优化用户体验,图片来源于《饿了么的 PWA 升级实践》。
5. Service Worker 支持的所有事件
五、销毁 Service Worker
浏览器决定是否销毁 Service Worker。在无痕浏览中,当页面关闭时相应的 Service Worker 会被销毁,因此尽量不要在代码中留存全局变量。可以访问 chrome://inspect/#service-workers和 chrome://serviceworker-internals/ 来检查 Service Worker 是否已经停用。
小结
困扰 Web 用户多年的难题——丢失网络连接,从 APPCache 到 Service Worker,解决办法一直在完善。Service Worker 开启的服务工作线程,对如何步入 Web 应用开发之旅,提供了很棒的切入角度。
那么,如何从本文开始,更好的学习 Service Worker?结合更多其它技术博客与 Service Worker 的 API 文档会更好。本文图片素材、写作思路多取源于此。
相关代码
本文所有关于 Web Worker、Service Worker 的代码,均在我的 gist 中: