你想过没有,为什么手机 App 能离线使用,而大部分网页不行?其实,通过 PWA(Progressive Web App)技术,网页也能做到!今天,咱就来聊聊 PWA 的核心技术——Service Worker,手把手教你搭建一个离线也能用的网站。
什么是 Service Worker?
简单来说,Service Worker 就是一个在浏览器后台默默运行的脚本。它就像一个“中间人”,拦截并处理网页发出的所有请求。有了它,咱们就能实现离线缓存、消息推送等神奇的功能。
想象一下,你正在地铁上看一篇新闻,突然没信号了!普通网页肯定加载不出来,但如果这个网站用了 Service Worker,它就能从本地缓存中取出内容,让你继续阅读。是不是很酷?
Service Worker 的生命周期
要用好 Service Worker,得先搞懂它的“一生”:
- 注册(Registration):告诉浏览器,咱要用 Service Worker 了。
- 安装(Installation):Service Worker 开始下载并安装自己。
- 激活(Activation):安装完成后,Service Worker 正式上岗,开始控制页面。
这三个阶段,Service Worker 都会触发相应的事件,咱们可以利用这些事件来做一些事情,比如缓存文件、清理旧缓存等。
实战:打造离线新闻网站
光说不练假把式,接下来,咱们就用 Service Worker 来做一个简单的离线新闻网站。别担心,我会一步一步教你,保证你能学会。
1. 准备工作
首先,你需要一个简单的 HTML 页面(index.html),里面包含一些新闻标题和内容。再准备一个 JavaScript 文件(app.js),用来注册 Service Worker。最后,创建一个名为 service-worker.js 的文件,这就是咱们的 Service Worker 脚本。
index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>离线新闻</title>
<link rel="manifest" href="/manifest.json">
</head>
<body>
<h1>今日新闻</h1>
<ul>
<li>
<h2>新闻标题1</h2>
<p>新闻内容1...</p>
</li>
<li>
<h2>新闻标题2</h2>
<p>新闻内容2...</p>
</li>
</ul>
<script src="app.js"></script>
</body>
</html>
app.js:
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('/service-worker.js')
.then(function(registration) {
console.log('Service Worker 注册成功:', registration.scope);
})
.catch(function(error) {
console.log('Service Worker 注册失败:', error);
});
});
}
这段代码的意思是,如果浏览器支持 Service Worker,就注册 /service-worker.js
这个文件。
2. 编写 Service Worker 脚本
重头戏来了!咱们要开始编写 service-worker.js
文件,实现离线缓存功能。
const CACHE_NAME = 'my-news-cache-v1';
const urlsToCache = [
'/',
'/index.html',
'/app.js',
'/style.css', // 如果你有样式文件
// 其他需要缓存的资源
];
// 安装事件
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open(CACHE_NAME)
.then(function(cache) {
console.log('缓存已打开');
return cache.addAll(urlsToCache);
})
);
});
// 激活事件
self.addEventListener('activate', function(event) {
//这里一般用来清理旧的缓存,暂时不做处理。
});
// fetch 事件
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request)
.then(function(response) {
// 如果缓存中有,就直接返回缓存
if (response) {
return response;
}
// 如果缓存中没有,就发起网络请求
return fetch(event.request);
})
);
});
这段代码做了几件事:
- 定义缓存名称和需要缓存的文件列表:
CACHE_NAME
是缓存的唯一标识,urlsToCache
列出了需要缓存的文件。 - 监听 install 事件:在 Service Worker 安装时,打开缓存并将文件添加到缓存中。
- 监听 activate 事件:暂时不做处理。
- 监听 fetch 事件:这是 Service Worker 的核心!每当网页发起请求时,都会触发这个事件。咱们在这里判断请求的资源是否在缓存中,如果在就直接返回缓存,否则发起网络请求。
3. 运行和测试
现在,你可以用一个简单的 HTTP 服务器(比如 Python 的 http.server
)来运行你的网站。打开浏览器,访问你的网站,然后打开开发者工具,看看 Service Worker 是否注册成功。
接下来,你可以尝试断开网络,刷新页面,看看新闻是否还能正常显示。如果一切正常,恭喜你,你已经成功构建了一个离线可用的网站!
###4. 清理旧缓存
随着网站的更新,我们需要清理旧的缓存,以节省用户的存储空间。在activate
事件中执行此操作:
self.addEventListener('activate', function(event) {
const cacheWhitelist = [CACHE_NAME]; // 白名单,保留当前版本的缓存
event.waitUntil(
caches.keys().then(function(cacheNames) {
return Promise.all(
cacheNames.map(function(cacheName) {
if (cacheWhitelist.indexOf(cacheName) === -1) {
// 如果缓存名称不在白名单中,就删除它
return caches.delete(cacheName);
}
})
);
})
);
});
每次更新 Service Worker 时,记得修改 CACHE_NAME
,比如从 v1
改为 v2
,这样旧的缓存就会被自动清理。
5. 缓存策略
上面的例子中,咱们使用了最简单的“Cache First”(缓存优先)策略。除了这种策略,还有其他几种常用的缓存策略:
- Network First(网络优先):先尝试从网络获取,如果失败再从缓存中获取。
- Cache Only(仅缓存):只从缓存中获取,如果缓存中没有就直接返回失败。
- Network Only(仅网络):只从网络获取,不使用缓存。
- Stale-While-Revalidate(后台更新):先返回缓存中的内容,同时在后台发起网络请求更新缓存。这种策略可以保证速度,但可能会显示旧的内容。
你可以根据你的网站需求,选择合适的缓存策略。 比如,对于不经常变化的内容,如图片、样式表等使用缓存优先,对于需要实时更新的内容,比如api数据,使用网络优先。
6. manifest.json
为了让你的网站更像一个 App,你可以添加一个 manifest.json
文件,定义网站的名称、图标、启动方式等。
{
"name": "我的离线新闻",
"short_name": "新闻",
"icons": [
{
"src": "/images/icon-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/images/icon-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"start_url": "/index.html",
"display": "standalone",
"theme_color": "#ffffff",
"background_color": "#ffffff"
}
在HTML中引用manifest文件。
<link rel="manifest" href="/manifest.json">
总结
Service Worker 是一个强大的工具,可以帮助我们构建更好的 Web 体验。通过本文的介绍,相信你已经对 Service Worker 有了一定的了解,并掌握了如何构建一个简单的离线网站。当然,Service Worker 的功能远不止这些,还有很多高级用法等待你去探索! 比如结合Cache API可以更精细化地控制缓存。 快去试试吧,让你的网站也能“飞”起来!