如果一个web app的某个文件特别大,为了减少网络流量,其实我们可以使用ServiceWorker将文件缓存到浏览器本地;每次读取这个大文件的时候,如果已经下载过了就直接读取本地的,加快页面加载。
其实非常简单,写一个 sw.js
放在web的根目录下。
// 定义需要缓存路径的正则表达式
var rules = [
new RegExp('/space/daily/soundfont/.*')
];
// 每次版本更新以后就更新version就好了
var version = 'v0.0.1';
// 清理不需要的缓存版本
self.addEventListener('activate', function (event) {
var cacheKeeplist = [version];
event.waitUntil(
caches.keys().then(function (keyList) {
return Promise.all(keyList.map(function (key) {
if (cacheKeeplist.indexOf(key) < 0) {
return caches.delete(key);
}
}));
})
);
});
self.addEventListener('fetch', function (event) {
event.respondWith(
caches.match(event.request).then(function (response) {
return response || fetch(event.request).then(function (netres) {
// 检查url是否匹配正则表达式
// 当然,这里有个bug就是没有检测protocol和hostname
var path = '/' + event.request.url.split('/').slice(3).join('/');
var match = false;
for (var i = 0, n = rules.length; i < n; i++) {
if (rules[i].test(path)) {
match = true;
break;
}
}
if (!match) return netres;
// 将指定可以缓存的path内容缓存起来
return caches.open(version).then(function (cache) {
cache.put(event.request, netres.clone());
return netres;
}); // caches.open
}); // fetch
}) // caches.match
);
});
在需要本地cache的页面加入:
function doMoreThings(firstTime) { ... }
if ('serviceWorker' in window.navigator) {
window.navigator.serviceWorker.getRegistrations().then(function (sws) {
cache();
if (sws.length === 0) {
doMoreThings(true);
} else {
doMoreThings(false);
}
function cache() {
window.navigator.serviceWorker.register('/sw.js', { scope: '/' }).then(
function () {
console.log('service worker is ready ...');
}, function (err) {
console.error('service worker:', err);
}
);
}
}, function () {
// 注册ServiceWorker失败
doMoreThings(null);
});
} else {
// 不支持ServiceWorker
doMoreThings(null);
}
要注意的是,ServiceWorker在127.0.0.1上可以HTTP,其他情况下是需要HTTPS环境的。