先上两个链接(详细解说请见):

AppCache

ServiceWorkers


下面上菜(例子),鉴于AppCache已经从 Web 标准中删除, 先说 ServiceWorkers:

ServiceWorkers, 在html中直接调用了 navigator.serviceWorker.register.

这里有个要特别注意的:

  • serviceWorker 的 js 文件所在的目录即为最大的 scope
  • 在 scope 下的文件及这些文件及其加载的文件(如index.html在scope下,但加载了第三方图片)都会被 serviceWorker 缓存
  • 故而 serviceWorker 文件一定要在 html 文件的同一个目录或者父级目录中, 否则无法缓存 html 文件, 即会导致无法离线访问!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!DOCTYPE HTML>
<html>
<head>
<link rel="stylesheet" type="text/css" href="/css/test-manifest.css" >
</head>
<body>
test-serviceworker
<img src="https://lh4.googleusercontent.com/XX2Wn8SS8gcv9V1AVRJA2e1MeXaKD4OpnQ7eny2smq5WZZF_jwgI2NYvS5GA-OW35syQ63V-TspyDA=s600" alt="">
</body>
<script type="text/javascript">
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/html/test-serviceworker.js', { }).then(function(reg) {
console.log(reg);
if(reg.installing) {
console.log('Service worker installing');
} else if(reg.waiting) {
console.log('Service worker installed');
} else if(reg.active) {
console.log('Service worker active');
}
}).catch(function(error) {
console.log('Registration failed with ' + error);
});
}
</script>
</html>
test-serviceworker.js 文件的内容

该文件一定要在 html 文件的同一个目录或者父级目录中, 否则无法缓存 html 文件, 即会导致无法离线访问!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open('v2').then(function(cache) {
return cache.addAll([
'/html/test-serviceworker.html',
'/css/test-manifest.css'
]);
})
);
});

self.addEventListener('fetch', function(event) {
event.respondWith(caches.match(event.request).then(function(response) {
if (response !== undefined) {
return response;
} else {
return fetch(event.request).then(function (response) {
// response may be used only once
// we need to save clone to put one copy in cache
// and serve second one
let responseClone = response.clone();

caches.open('v2').then(function (cache) {
cache.put(event.request, responseClone);
});
return response;
}).catch(function (err) {
console.log(err);
// return caches.match('/sw-test/gallery/myLittleVader.jpg');
});
}
}));
});


AppCache, 我用 nodejs(koa) 写的appcache文件:

1
2
3
4
5
6
7
8
router.get('/cache.appcache', async (ctx, next) => {
ctx.response.set('Content-Type', 'text/cache-manifest');
ctx.body = [
`CACHE MANIFEST${process.env.UPDATE_MANIFEST}`,
"/css/test-manifest.css",
"/js/test-manifest.js"
].join("\n");
})
process.env.UPDATE_MANIFEST 是一个数字,用来更新缓存文件.
下面的代码将该数字转为对应数量的空格字符串:
1
2
const num = process.env.UPDATE_MANIFEST;
process.env.UPDATE_MANIFEST = (new Array(Number(num?num:0)).fill(" ")).join("");

总结一下啊,不知道你有没有发现, ServiceWorkers 基本是前端的活, AppCache 基本是后端的活.
单纯这一条就让我觉得 ServiceWorkers 比 AppCache 更优秀! 不过 ServiceWorkers 在 Safari 浏览器上还不受支持.