pwa-之service worker 基本概念
pwa-之service worker 离线文件处理
本章包含以下知识点
- 显示离线页面
- 加载离线图片
- 加载离线css
- 多个fetch处理事件调用
简介
网站图片由于不确定的原因,可能无法访问,这给用户一个错觉,就是你的网站出了问题
其他诸如css,js文件都是网站必不可少的资源,本章我们来学些如何加载这些资源
首先让我们来看看一个离线页面
显示离线页面
- 创建一个html页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Custom Offline Page</title>
</head>
<body>
<p>Registration status: <strong id="status"></strong></p>
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register(
'service-worker.js',
{ scope: './' }
).then( function(serviceWorker) {
document.getElementById('status').innerHTML = 'successful';
}).catch(function(error) {
document.getElementById('status').innerHTML = error;
});
} else {
document.getElementById('status').innerHTML = 'unavailable';
}
</script>
</body>
</html>
- 创建一个service-worker.js文件
var version = 1;
var currentCache = {
offline: 'offline-cache' + version
};
var offlineUrl = 'offline.html';
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open(currentCache.offline).then(function(cache) {
return cache.addAll([
'offline.svg',
offlineUrl
]);
})
);
});
self.addEventListener('fetch', function(event) {
// request.mode = navigate isn't supported in all browsers
// so include a check for Accept: text/html header.
if (event.request.mode === 'navigate' ||
(event.request.method === 'GET' &&
event.request.headers.get('accept').includes('text/html'))) {
event.respondWith(
fetch(createCacheBustedRequest(event.request.url)).catch(function(error) {
// Return the offline page
console.log('Fetch failed. Returning offline page instead.', error);
return caches.match(offlineUrl);
})
);
} else {
// Respond with everything else if we can
event.respondWith(caches.match(event.request)
.then(function (response) {
return response || fetch(event.request);
})
);
}
});
function createCacheBustedRequest(url) {
var request = new Request(url,
{cache: 'reload'}
);
// See https://fetch.spec.whatwg.org/#concept-request-mode
// This is not yet supported in Chrome as of M48, so we need to explicitly check to see
// if the cache: 'reload' option had any effect.
if ('cache' in request) {
return request;
}
// If {cache: 'reload'} didn't have any effect, append a cache-busting URL parameter instead.
var cacheBustingUrl = new URL(url, self.location.href);
cacheBustingUrl.search += (cacheBustingUrl.search ? '&' : '') + 'cachebust=' + Date.now();
return new Request(cacheBustingUrl);
}
- 创建offline.html页面
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Offline</title>
</head>
<body>
<div style="text-align:center; margin-top:40px;">
<img src="offline.svg" width="80" height="80" />
<p>Whoops! Your internet connection is not working.</p>
<p>Please check your network connection and try again.</p>
<div>
</body>
</html>
- 创建offline.svg文件
<svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" viewBox="0 0 25 25">
<path d="M16 0l-3 9h9l-1.866 2h-14.4L16 0zm2.267 13h-14.4L2 15h9l-3 9 10.267-11z" fill="#04b8b8"/>
</svg>
- 打开index.html页面。
- 勾上network->offline:刷新页面,显示如图
实现原理
使用cache Api,预先缓存offline.html和offline.svg。当网络不通时,html请求走到cache方法里面去,然后响应的是缓存好的offline.html。offline.html又请求已经缓存好的offline.svg。所以正常显示。
加载离线图片
- 创建index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Offline Images</title>
</head>
<body>
<p>Registration status: <strong id="status"></strong></p>
<img src="packt-logo.png" alt="logo">
<script src="index.js"></script>
</body>
</html>
- 创建index.js
'use strict';
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register(
'service-worker.js',
{ scope: './' }
).then( function(serviceWorker) {
document.getElementById('status').innerHTML = 'successful';
}).catch(function(error) {
document.getElementById('status').innerHTML = error;
});
} else {
document.getElementById('status').innerHTML = 'unavailable';
}
- 创建service-worker.js
var version = 1;
var cacheName = 'static-' + version;
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open(cacheName).then(function(cache) {
return cache.addAll([
'index.html',
'packt-logo.png'
]);
})
);
});
self.addEventListener('fetch', function(event) {
event.respondWith(caches.match(event.request));
});
访问/Chapter%202/02/index.html,然后打开offline。页面仍然可以正常显示。
记住一定要加上index.html。大部分的服务器会把/
指向到index.html
。这样子我们的页面缓存不会生效。
加载离线css
- 创建index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Offline CSS</title>
<link rel="stylesheet" href="style-2.css">
<link rel="stylesheet" href="style-1.css">
</head>
<body>
<p>Registration status: <strong id="status"></strong></p>
<script async>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register(
'service-worker.js',
{ scope: './' }
).then( function(serviceWorker) {
document.getElementById('status').innerHTML = 'successful';
}).catch(function(error) {
document.getElementById('status').innerHTML = error;
});
} else {
document.getElementById('status').innerHTML = 'unavailable';
}
</script>
</body>
</html>
- 创建service-worker.js
var version = 1;
var cacheName = 'static-' + version;
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open(cacheName).then(function(cache) {
return cache.addAll([
'index.html',
'style-2.css'
]);
})
);
});
self.addEventListener('fetch', function(event) {
if (/index/.test(event.request.url) || /style-2/.test(event.request.url)) {
event.respondWith(caches.match(event.request));
}
});
- 创建style-1.css
body {
background-color: lightgreen;
}
- 创建style-2.css
body {
background-color: red;
}
同样访问html可以看到绿色的背景,offline之后显示的红色的背景。
一定要访问index.html
啊,不然不会成功
多个fetch事件调用
fetch事件和js其他事件一样都是可以注册多次的。
- 创建index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Mutiple Fetch</title>
</head>
<body>
<p>Registration status: <strong id="status"></strong></p>
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register(
'service-worker.js',
{ scope: './' }
).then( function(serviceWorker) {
document.getElementById('status').innerHTML = 'successful';
}).catch(function(error) {
document.getElementById('status').innerHTML = error;
});
} else {
document.getElementById('status').innerHTML = 'unavailable';
}
</script>
</body>
</html>
- 创建service-worker.js
var cookFetchHandler = function(event) {
console.log('DEBUG: Inside the /cook handler.');
if (event.request.url.indexOf('/cook/') > 0) {
event.respondWith(new Response('Fetch handler for /cook'));
}
};
var cookBookFetchHandler = function(event) {
console.log('DEBUG: Inside the /cook/book handler.');
if (event.request.url.endsWith('/cook/book')) {
event.respondWith(new Response('Fetch handler for /cook/book'));
}
};
var fetchHandlers = [cookBookFetchHandler, cookFetchHandler];
fetchHandlers.forEach(function(fetchHandler) {
self.addEventListener('fetch', fetchHandler);
});
浏览器里面访问
然后访问/cook/
,是/cook/
不是/cook
访问/cook/book
关注我的微信公众号,更多优质文章定时推送
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。