Service Worker¶
统计信息:字数 5479 阅读11分钟
简介¶
Service worker 是后台运行的一个 JavaScript 脚本。它由前台页面的 JavaScript 脚本新建,运行在独立的线程。它是异步的,不会造成页面的堵塞,可以发出通知(push notification),但拿不到 DOM。它要求页面必须使用 HTTPS 协议。
Service Worker 一共有 6 种状态。
- parsed
- installing
- installed
- activating
- activated
- redundant
登记 Service Worker。
/* In main.js */
if ("serviceWorker" in navigator) {
navigator.serviceWorker
.register("./sw.js")
.then(function (registration) {
console.log("Service Worker Registered", registration);
})
.catch(function (err) {
console.log("Service Worker Failed to Register", err);
});
}
一旦登记成功,Service Worker 的状态就变成了parsed
。
然后,浏览器尝试安装 Service Worker 脚本,这时它的状态就变成了installing
。
/* In main.js */
navigator.serviceWorker.register("./sw.js").then(function (registration) {
if (registration.installing) {
// Service Worker is Installing
}
});
一旦进入安装阶段,Service Worker 脚本会接收到一个install
事件。这个事件的回调函数里面,可以缓存静态文件。
/* In sw.js */
var cacheName = "your-first-service-worker";
var urlsToCache = [
"/",
"css/tachyons.min.css",
"img/andre-benz-248755.jpg",
"img/andre-benz-250740.jpg",
"img/andre-benz-256762.jpg",
"img/redd-angelo-230297.jpg",
];
self.addEventListener("install", function (event) {
// Perform install steps
event.waitUntil(
caches.open(cacheName).then(function (cache) {
console.log("Opened cache");
return cache.addAll(urlsToCache);
})
);
});
上面代码中,事件对象有一个event.waitUntil()
方法,只有这个方法内部的 Promise 变成resolved
以后,installing
事件才会成功。如果 Promise 变成rejected
,installing
事件就会失败,Service Worker 变成redundant
状态。
/* In sw.js */
self.addEventListener('install', function(event) {
event.waitUntil(
Promise.reject(); // Failure
);
});
如果安装成功,Service Worker 就变成installed
状态,或者也叫waiting
状态。这时,Service Worker 是有效的,但还没有被激活。它还不受当前文档控制,而是等待接受控制的状态。
主脚本之中可以检查,是否处于waiting
状态。
/* In main.js */
navigator.serviceWorker.register("./sw.js").then(function (registration) {
if (registration.waiting) {
// Service Worker is Waiting
}
});
这时可以通知用户升级版本,或者为他们自动更新。
以下几种情况,Service Worker 会进入activating
状态。
- 当前没有活跃的 Worker
- Service Worker 脚本里面,调用了
self.skipWaiting()
方法 - 用户离开当前页面,因此释放了前一个活跃的 worker
- 经过一段时间,前一个活跃的 worker 已经释放
进入activating
状态时,Service Worker 脚本会接收到active
事件,通常在这个事件的回调函数里面清除旧缓存。
/* In sw.js */
self.addEventListener("activate", function (event) {
event.waitUntil(
// Get all the cache names
caches.keys().then(function (cacheNames) {
return Promise.all(
// Get all the items that are stored under a different cache name than the current one
cacheNames
.filter(function (cacheName) {
return cacheName != currentCacheName;
})
.map(function (cacheName) {
// Delete the items
return caches.delete(cacheName);
})
); // end Promise.all()
}) // end caches.keys()
); // end event.waitUntil()
});
上面代码中,也有一个event.waitUntil()
方法,只有它里面的 Promise 变成resolved
,激活才能成功。否则,就会激活失败,Service Worker 变成redundant
。
如果激活成功,Service Worker 就变成active
状态,这时 Service Worker 会完全控制文档。我们可以这样检查是否进入这个状态。
/* In main.js */
navigator.serviceWorker.register("./sw.js").then(function (registration) {
if (registration.active) {
// Service Worker is Active
}
});
一旦 Service Worker 激活,它就能处理 fetch 和 message 事件。
/* In sw.js */
self.addEventListener("fetch", function (event) {
// Do stuff with fetch events
});
self.addEventListener("message", function (event) {
// Do stuff with postMessages received from document
});
由于以下原因,Service Worker 会变成redundant
状态。
- installing 事件失败
- activating 事件失败
- 一个新的 Service Worker 取代了当前活跃的 Service worker
用户发出请求时,会触发fetch
事件。
// Fetch the contents and reply with 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);
})
);
});
参考链接¶
- The Service Worker Lifecycle, by Ire Aderinokun
- Your first service worker, by Nicola