配饭短文:离线Web应用入门

2,376 阅读4分钟

前言

最近笔者有些精神恍惚,人生中一些印象深刻的事情,像PPT一样从脑海中一一闪过,比如:

  • 小学时候作为劳动委员,常年负责掏学校里一个蘑菇形的垃圾桶,结果有一天捡到了好几张一块钱,贼开心。
  • 大学里有一天下晚自习,一推门,瞧见一个天使般面容的女子,贼开心。
  • 有一次通宵加班(非快狗打车),早上回家时,反向地铁居然有座位,贼开心。
  • 有一次被提了一个bug:
    image

(事实证明文字顺序并不影响阅读)作为一个被困在Webview里的FE,我沉默了,贼不开心。

----------以上是暖场----------

无网络时,前端真的什么都做不了吗?本文滚动条以及直觉告诉你,那一定不是的。
联想到几个月前写的一篇无人问津的文章:《Service Worker从入门到出门》(这是广告,方便的话请去点赞,对您没什么好处,但我会高兴),笔者意识到,如果不计代价的话,借助Service Worker,那个bug里要求的效果,其实也不是不可能实现。

本文决定,不纠结于那个bug,而针对无网络的极限场景,用尽量少的代码,实现一个demo级别的离线Web应用。

一点说明

所谓的离线应用,不是指一直离线,一直没网的话,那还玩些什么呢?而是指一开始用户是有网络的,但是用户因为走进地铁,或者买了近两年的iPhone,突然就没网了,此时,让页面展示一些缓存的内容。

理清思路、抓住关键

实现一个离线Web应用的关键在于:拦截请求缓存资源

在此假设读者了解Service WorkerCacheStorage的基础。

简单来讲,如果不考虑HTTP缓存的话,一个普通Web App获取静态资源是从服务器获取的。但是Service Worker相当于在浏览器的出口加了一层代理,有着拦截并处理请求的能力,这使得我们有机会选择资源是从服务器取还是从CacheStorage中取。
CacheStorage既然作为一种缓存,那大概就要遵从“如果命中缓存则返回缓存中的资源,否则从远处取”的基本策略。
具体到一个Web应用,静态资源可以粗略分为html和其它(js、css、图片等),html作为应用入口,有着它的特殊性。实现离线应用的关键在于缓存入口html,这是实现离线应用的核心思路。设想一下,如果html保存在本地,那在无网络的情况下,浏览器也是可以打开的,至于html引用的其它静态资源,如果缓存过,那也是可以访问的。

代码

首先,初始化一个项目,在此以Vue项目为例,在入口html中注册service worker:

  <script>
    if ('serviceWorker' in navigator) {
      window.addEventListener('load', function () {
        navigator.serviceWorker.register('/demo/service-worker.js').then(function (reg) {
          console.log('service-worker.js注册成功');
        }, function (err) {
          console.log('service-worker.js注册失败');
        });
      });
    }
  </script>

service-worker.js代码:

// 每次更新需要更新版本号
const cacheVersion = 'v1';

// service worker激活时的初始化操作,非关键代码,可以不看
self.addEventListener('activate', function (event) {
    event.waitUntil(
        caches.keys().then(function (cacheNames) {
            return Promise.all(
                cacheNames.map(function (cacheName) {
                    // 如果当前版本和缓存版本不一致,则删除其它版本的cache
                    if (cacheName !== cacheVersion) {
                        return caches.delete(cacheName);
                    }
                })
            );
        })
    );
});

// 核心代码,最好看一看
self.addEventListener('fetch', function (event) {
    event.respondWith(
        caches.match(event.request)
            .then(function (response) {
                // 如匹配了cache,则直接返回cache中的资源
                // 否则fetch资源并缓存下来
                return response || fetch(event.request).then(function (r) {
                    caches.open(cacheVersion).then(function (cache) {
                        cache.put(event.request, r);
                    });
                    return r.clone();
                });
            })
    );
});

成果展示

代码部署好后,访问页面,刷新,可以看到:cacheStorage中的静态资源已经缓存成功:

image
然后我们断网,刷新,可以发现:页面还是可以访问的,静态资源的响应状态码是200,但标注了(from ServiceWorker)
image

总结

所以,如此少的代码,就可以实现一个离线Web应用,但是从Demo到实际应用,还有好长的路要走。无论如何,本文所述的是离线Web应用的基本思路和方法。希望大家能够喜欢,甚至点赞。(温馨提示:点赞并不花钱)

image

关于我们

快狗打车前端团队专注前端技术分享,定期推送高质量文章,欢迎关注点赞。 文章同步发布在公众号哟,想要第一时间得到最新的资讯,just scan it !

公众号二维码