正常的开场本应该是“什么是Service Worker”,但Service Worker往往会和PWA被一同提起。无论屏幕前的你是有丰富PWA开发经验的大佬,还是从没有听过这个概念的小佬,本文都有义务讲清楚Service Worker和PWA的关系,在此假设大家仅仅是一个对Service Worker感兴趣的前端工程师,并没有丰富的相关经验。
另外,本文力求抓住重点,理清思路,并不是一篇偏技术流的文章,如果您只是想了解某些API怎么用,或者遇到了什么问题需要解决,那本文将浪费您5-20分钟的时间,点个赞之后就快快关掉吧~
PWA全称 Progressive Web Apps
,直译过来是“渐进式网络应用程序”,看到这个翻译,大多数人应该是不接受的,因为我们并不能从字面上理解PWA是什么。以下是维基百科对PWA的定义:
渐进式网络应用程序(英语:Progressive Web Apps,简称:PWA)是一种普通网页或网站架构起来的网络应用程序,但它可以以传统应用程序或原生移动应用程序的形式展示给用户。
这也是一个正确但不充分的定义,不能很好描述PWA的真实特性。
经过一段时间的整理,在此表达一下本文对PWA的理解:
Web和App都懂,但Progressive是几个意思?说起“Progressive 渐进式”,想必大家或多或少听过一些关于Web应用“平稳退化、渐进增强”的设计理念,由于浏览器对于Web标准的跟进会有不同程度的滞后(更有甚者不但不跟进还要乱搞),很多优秀的新特性老旧浏览器并不支持,所以开发者有时会采取渐进式的策略,充分利用新特性,为支持新特性的浏览器提供更完善的功能和更好的体验(
让一部分人先富起来?
)。PWA之P,大约就是这个意思。
众所周知,Web应用和Native应用原本井水不犯河水,二者有着各自的应用场景和优势。但随着浮夸的移动互联网时代的到来,贪婪的人类想要取长补短,兼顾二者的优点,乐此不疲地发明了一坨又一坨血统不纯的烂尾混合开发技术,在此不一一列举,大家都懂。PWA是为了达到同样目的的另一种尝试,它绝不是革命性的技术,只是传统Web应用向Native应用的又一次疯狂试探,也只是一次不大不小的进化而已。但区别于混合开发技术,PWA是血统纯正的Web技术的自然延伸,背后有相关Web标准支撑。
这一次,PWA相对于传统Web应用,主要在以下几个方面变得更强:
CacheStorage
,PWA可以提升Web应用在网络条件不佳甚至离线时的用户体验和性能。 简单总结:PWA是Web应用的自然进化,Service Worker是PWA的关键。
Service Worker
是浏览器在后台独立于网页运行的、用JavaScript编写的脚本。
让我们来看看最小的Service Worker长什么样,以及怎么跑起来:(朋友们请不要看见代码块就自动略过,请相信我真的没有几行)
// 不起眼的一行if,除了防止报错之外,也无意间解释了PWA的P: // 如果浏览器不支持Service Worker,那就当什么都没有发生过 if ('serviceWorker' in navigator) { window.addEventListener('load', function () { // 所以Service Worker只是一个挂在navigator对象上的HTML5 API而已 navigator.serviceWorker.register('/service-worker.js').then(function (registration) { console.log('我注册成功了666'); }, function (err) { console.log('我注册失败了'); }); }); } 复制代码
以上代码,在load事件触发后,下载并注册了service-worker.js这个文件,Service Worker的逻辑,就写在这里:
// service-worker.js // 虽然可以在里边为所欲为地写任何js代码,或者也可以什么都不写, // 都不妨碍这是一个Service Worker,但还是举一个微小的例子: self.addEventListener('fetch', function (event) { if (//.png$/.test(event.request.url)) { event.respondWith(fetch('/images/支付宝收款码.png')); } }); 复制代码
受到身后TL大哥桌面上扫码提需求支付宝二维码的启发,以上代码,可以拦截网页上所有png图片的请求,返回你的支付宝收款码图片,只要用户够多,总会有人给你打钱的。
代码中的self是第一个匪夷所思的地方,看起来是一个未定义的变量,但稍加思索我们就可以意识到这是一个关键字,类似于window或global,代表该Service Worker自身,所以想要玩转Service Worker,是需要学习它的API的。
我们暂且不去仔细看那些需要背的API,只需要记得这段代码做了什么,它像一个middleware一样,拦截并处理了HTTP请求,此时的Service Worker,可以理解为一个客户端代理。由于代码是人为编写的,开启了无限可能。另外,最可怕的就是流氓会武术了,所以Service Worker要求HTTPS,注意那个"S",但为了开发调试方便,localhost除外。
简单总结:
按照一篇文章的一贯节奏,到这个该深入的阶段,阅读体验往往突然变差,为了避免这种情况,不得不提的Service Worker生命周期话题,推荐大家去其它地方阅读,这种文章已经很多了,本文作者认为,此处可以写但没必要,并且没有信心写得比它们好,写了反而有抄袭凑字之嫌,所以在此仅仅贴出MDN的图,并简单总结(微笑)。
简单总结:
当我们掌握了Service Worker的基础,就可以尝试着应用了,在此着重介绍一些关乎网页性能方面的应用,不会粘贴代码,而主要谈谈思路和方法。
Service Worker的一大应用是可以利用CacheStorage API来缓存js、css、字体、图片等静态文件。我们可以在Service Worker的install阶段,指定需要缓存的具体文件,在fetch事件的回调函数中,检查请求的url,如果匹配了已缓存的资源,则不再从服务端获取,以此达到提升网页性能的目的。常用的构建PWA的 App Shell
架构,就是利用这种方式实现的。
需要注意的是,性能的提升是相对于完全没有缓存的情况来讲的,而浏览器本身有着相对完善的HTTP缓存机制。所以使用Service Worker缓存,并不能使我们已经相对完善的架构有立竿见影的性能提升,Service Worker缓存真正有意义的地方在于,利用它可以更精准地、以编码方式控制缓存,如何缓存、缓存什么、如何更新缓存,完全取决于代码如何写,所以这提供了很大的自由度,但同时也带来维护成本。它只是换了一种缓存方式,而不是从无到有的突破。
上一部分我们只是缓存了js、css、字体、图片等静态资源,但如果我们将首页index.html也缓存呢?那结果是我们的网页甚至可以支持离线浏览。
听起来很棒是吧?请坐下,这里有一个巨大的问题:假定我们的主页是index.html,里边注册了service-worker.js,service-worker.js中缓存了index.html以达到离线浏览的目的,那么问题来了,在我们下次上线,死活是不会生效的,因为用户访问的总是缓存过的index.html,是不是很尴尬?我们需要更新service-worker.js来重新缓存index.html,虽然网上也有一些方案解决这种问题,但似乎异常纠结,让我们难免怀疑离线浏览是否有意义。
下面的做法似乎更好一些:既然我们现在具有了离线缓存文件和拦截HTTP请求的能力,那我们可以在Service Worker安装时,缓存一个offline.html,类似于404页面。离线状态下,我们访问index.html文件的请求是会失败的,在这个时机,我们返回offline.html文件展示给用户,至于具体展示些什么,取决于具体需求,甚至可以像chrome离线时那样,做一个小游戏来调戏没有网络的用户。
Service Worker只是提供了一些厉害的功能,但如何应用完全取决于开发者,如果脑洞大开,完全有可能提供令人耳目一新的体验。在此仅仅举一个小例子:
我们知道,网页中图片是很消耗带宽资源的,用户等待网站加载,很多时候都是在等图片,而大多数放在CDN上的图片,都支持添加后缀参数获取不同分辨率照片的功能。假设我们有办法知道一个用户的网络条件的好坏(至于如何判断一个用户的网络条件,是另外一件事,可以让用户选择,也可用技术手段解决),把用户分级,暂且分为两级:网速快的和网速慢的。我们把网速级别信息放到HTTP请求的header中(或其它你想得到的合适的地方),当发起图片请求的时候,我们有机会拿到用户的网络级别,如果是网速快的用户,我们通过后缀参数返回CDN上高分辨率的图片,反之相反。
这样的结果是网速快的用户可以看到更清晰的照片,而网速慢的用户虽然看到的照片清晰度差,但可以更早地看到照片,不必经过漫长的等待。
以上的讨论,都是纸上谈兵,当我们真的要在生产环境实际应用的时候,仔细想想,就会发现事情不是那么简单,在此列举一些需要注意和考虑的地方。
接下来让我们来谈谈Service Worker的应用场景,或者说什么样的情况才需要上Service Worker,这很好理解,但很重要,我们不能拿着锤子,看什么都像钉子。
简单总结:Service Worker的初衷是极致优化用户体验,是用来锦上添花的,技术只是技术,但实际应用前,应考虑成本和收益。
本文简单谈了谈PWA和Service Worker的关系、Service Worker的基础、Service Worker的生命周期和事件、Service Worker的简单应用,以及实际应用中的注意事项和场景,只是一篇入门级的科普文章,大家可根据自己感兴趣的具体方面,去深入了解。鉴于本文作者是个才疏学浅的喷子,文章难免有所疏漏甚至误导,欢迎指正。
另外在码字过程中,有一些感想在此和大家分享:
事已至此,本文已离题无误,至于Service Worker,用来吹牛实在是再合适不过了,如果真要大规模应用,大家可能需要结合具体情况综合考虑。但无论如何,作为一项技术储备还是有必要的。不说了,外卖凉了。那你还愣着干嘛?快赶快点赞评论加收藏啊!
快狗打车前端团队专注前端技术分享,定期推送高质量文章,欢迎关注点赞。