利用 Service worker 创建一个非常简单的离线页面让我们想像以下情景: 我们此时在一辆通往农村的火车上, 用移动设备看着一篇很棒的文章。
与此同时, 当你点击“ 查看更多” 的链接时, 火车忽然进入了隧道, 导致移动设备失去了网络, 而 web 页面会呈现出类似以下的内容: 这是相当令人沮丧的体验! 幸运的是, web 开发者们能通过一些新特性来改善这类的用户体验。
我最近一直在折腾 Service Workers, 它给 web 带来的无尽可能性总能给我惊喜。
Service Workers 的美妙特质之一是允许你检测网络请求的状况, 并让你作出相应的响应。
在这篇文章里, 我打算用此特性检查用户的当前网络连接状况, 如果没连接则返回一个超级简单的离线页面。
尽管这是一个非常基础的案例, 但它能给你带来启发, 让你知道启动并运行该特性是多么的简单! 如果你没了解过 Service Worker, 我建议你看看此 Github repo, 了解更多相关的信息。
在该案例开始前, 让我们先简单地看看它的工作流程: 在用户首次访问我们的页面时, 我们会安装 Service Worker, 并向浏览器的缓存添加我们的离线 html 页面 然后, 如果用户打算导航到另一个 web 页面( 同一个网站下), 但此时已断网, 那么我们将返回已被缓存的离线 html 页面 但是, 如果用户打算导航到另外一个 web 页面, 而此时网络已连接, 则能照常浏览页面让我们开始吧假如你有以下 html 页面。
这虽然非常基础, 但能给你总体思路。 < !DOCTYPE html > 1 < !DOCTYPE html > 接着, 让我们在页面里注册 Service Worker, 这里仅创建了该对象。
向刚刚的 HTML 里添加以下代码。
< script > Register the service worker 注册 service worker
if (‘serviceWorker’ in navigator) {
navigator.serviceWorker.register(‘/service-worker.js’).then(function (registration) {
Registrationwassuccessful注册成功console.log(‘ServiceWorker registration successful with scope: ‘, registration.scope);
}).catch(function (err) {
registrationfailed: (注册失败: (console.log(‘ServiceWorker registration failed: ‘, err);
});
} < /script> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <script> Register the service worker 注册 service worker if ( ‘serviceWorker’ in navigator ) { navigator . serviceWorker . register ( ‘/service – worker.js ‘ ) . then ( function ( registration ) { Registration was successful 注册成功 console . log ( ‘
ServiceWorker registration successful with scope: ‘ , registration . scope ) ; } ) . catch ( function ( err ) { registration failed 🙁 注册失败 🙁 console . log ( ‘
ServiceWorker registration failed: ‘ , err ) ; } ) ; } </script>然后,我们需要创建 Service Worker 文件并将其命名为 ‘service-worker.js‘。我们打算用这个 Service Worker 拦截全部网络请求,以此检查网络的连接性,并根据检查结果向用户返回最适合的内容。’
usestrict ‘; varcacheVersion=1; varcurrentCache= { offline: ‘
offline – cache ‘ + cacheVersion }; const offlineUrl = ‘
offline – page.html ‘; this.addEventListener(‘
install ‘, event=> { event.waitUntil( caches.open(currentCache.offline).then(function(cache) { returncache.addAll([ ‘. / img / offline.svg ‘, offlineUrl ]); }) ); }); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ‘
use strict ‘ ; var cacheVersion = 1 ; var currentCache = { offline : ‘
offline – cache ‘ + cacheVersion } ; const offlineUrl = ‘
offline – page.html ‘ ; this . addEventListener ( ‘
install ‘ , event = > { event . waitUntil ( caches . open ( currentCache . offline ) . then ( function ( cache ) { return cache . addAll ( [ ‘. / img / offline.svg ‘ , offlineUrl ] ) ; } ) ) ; } ) ;在上面的代码中,我们在安装 Service Worker 时,向缓存添加了离线页面。如果我们将代码分为几小块,可看到前几行代码中,我为离线页面指定了缓存版本和URL。
如果你的缓存有不同版本,那么你只需更新版本号即可简单地清除缓存。
在大概在第12行代码,我向这个离线页面及其资源(如:图片)发出请求。
在得到成功的响应后,我们将离线页面和相关资源添加到缓存。
现在,离线页面已存进缓存了,我们可在需要的时候检索它。
在同一个ServiceWorker中,我们需要对无网络时返回的离线页面添加相应的逻辑代码。
this.addEventListener(‘
fetch ‘, event => { request.mode = navigate isn’
t supported in all browsers request.mode = naivgate 并没有得到所有浏览器的支持 so include a check
forAccept: text/htmlheader.因此对header的Accept: text/html进行核实
if (event.request.mode===’navigate’|| (event.request.method ===’GET’&&event.request.headers.get(‘accept’).includes(‘text/html’))) {
event.respondWith(fetch(event.request.url).catch(error=> {
Returntheofflinepage返回离线页面
returncaches.match(offlineUrl);
}));
} else {
Respondwitheverything
elseifwecan返回任何我们能返回的东西event.respondWith(caches.match(event.request).then(function (response) {
returnresponse||fetch(event.request);
}));
}
});
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 this.addEventListener(‘fetch’, event = > {
request.mode = navigate isn ‘t supported in all browsers request.mode = naivgate 并没有得到所有浏览器的支持 so include a check for Accept: text/html header. 因此对 header 的 Accept:text/html 进行核实 if ( event . request . mode === ‘
navigate ‘ || ( event . request . method === ‘
GET ‘ && event . request . headers . get ( ‘
accept ‘ ) . includes ( ‘
text / html ‘ ) ) ) {event.respondWith(fetch(event.request.url).catch(error = > { Return the offline page 返回离线页面 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 ) ; } ) ) ; } } ) ; 为了测试该功能,你可以使用 Chrome 内置的开发者工具。首先,导航到你的页面,然后一旦安装上了 Service Worker,就打开 Network 标签并将节流(throttling)改为 Offline。
(译者注:若将节流设置为 Offline 没效果,则可通过关闭网络或者通过360安全卫士禁止 Chrome 访问网络)如果你刷新页面,你应该能看到相应的离线页面!如果你只想简单地测试该功能而不想写任何代码,那么你可以访问我已创建好的 demo。
另外,上述全部代码可以在 Github repo 找到。我知道用在此案例中的页面很简单,但你的离线页面则取决于你自己!如果你想深入该案例的内容,你可以为离线页面添加缓存破坏( cache busting),如: 此案例。拓展阅读此外,还有几个很棒的离线功能案例。如:Guardian 构建了一个拥有 crossword puzzle(填字游戏)的离线 web 页面 – 因此,即使等待网络重连时(即已在离线状态下),也能找到一点乐趣。
我也推荐看看 Google Chrome Github repo,它包含了很多不同的 Service Worker 案例 – 其中一些应用案例也在这!然而,如果你想跳过上述代码,只是想简单地通过一个库来处理相关操作,那么我推荐你看看 UpUp。
这是一个轻量的脚本,能让你更轻松地使用离线功能。
评论前必须登录!
注册