PWA系列 -- 带你认识PWA
2018-11-21
# 前言
Chromium在2014.3已开始研发Service Workers,并于2014.11发布的Chrome for Android release 40正式支持。Alex Russell 2015.6在博客文章 Progressive Web Apps: Escaping Tabs Without Losing Our Soul 中正式提出PWA(Progressive Web App)的概念。Google 2016.12在北京/上海举办的GDD大力推广PWA相关技术,让PWA概念深入人心。在此之后的各种大型技术会议,PWA成了不可或缺的主题。iOS Safari 在2018.2发布的Safari Technology Preview Release 49宣布正式支持Service Workers,扫清了PWA发展的最大障碍。
PWA在各个主流浏览器/平台上的支持情况
2018年是PWA快速落地应用的一年。我们近期将会推送一系列文章介绍PWA技术以及该项技术在阿里体系内的实践及影响,敬请读者关注。
# PWA简介
Progressive Web Apps use modern web capabilities to deliver an app-like user experience. They evolve from pages in browser tabs to immersive, top-level apps, maintaining the web's low friction at every moment.
PWA基于通过先进的技术为Web应用带来接近本地应用的使用体验。基于PWA的Web应用从一个Web页面变为一个沉浸式的顶层应用,并且时刻保持着对网络的低依赖性。
PWA经过Google的大力推广,目前已经比较流行,业界也比较关注,有观望其发展趋势的也有已付诸实践的。这项技术能作为Google力推的技术方向,它需要得到公司的认同和支持,首先需要符合公司的理念或者战略利益。 Google公司在移动端有核心竞争力的产品 Android 和 Chromium OS,其中Android 是移动端的操作系统,而Chromium OS则是面向未来的云操作系统。目前Android在移动端的市场份额非常大,已远远超出iOS,甚至已超出80%。 Android现在可谓风光无限,但它不一定能代表未来,Google也不一定会放弃“浏览器即是操作系统”的理想。Google Chrome浏览器既可以运行在Android系统,也可以运行在Chromium OS系统。多方的统计数据显示,Google Chrome浏览器的市场份额已超越IE,成为全球第一大浏览器。问题是,如果没有了Web,浏览器该怎么办? 也就没有份额可言了。如果没有了浏览器,Google搜索怎么办? Google搜索广告收入历年来都是Google公司的主要收入来源,有些年份甚至超出90%。如果大部分的内容都困在超级App的孤岛,搜索引擎也将面临巧妇难为无米之炊的困境。
Web 在与Native比较时,很多时候都处于弱势,一个比较核心的点在于用户体验上的差异。 那么,Web 和 Native是否可以拥有同样的能力,同样的用户体验呢?这就是PWA的意义所在,打造与Native一致的Web体验。除了用户体验,PWA应用同样也能出现在系统设置里面。 从Google对PWA的态度来看,只要Natvie Apps具备的且必要的能力,它都愿意开放给Web Apps。
# PWA技术
# ServiceWorker
可扩展Web的设计原则是专注于为Web平台增加安全高效的底层功能。PWA的核心技术是ServiceWorker,ServiceWorker给前端开发者开放了内核大量的底层能力,比如,它给前端提供了细粒度操作请求缓存的底层原语,等同于给前端开放了操作HTTP Cache级别缓存的能力,与Fetch API结合,让前端具备了完全操控请求,响应,缓存的能力。后面会有一节专门介绍ServiceWorker技术。
# Fetch
XMLHttpRequest 是ajax的关键技术,可以局部交换客户端及服务器之间的数据,从根本上保证了Web页面的动态性,但它并不完美,在设计上存在缺陷,不符合职责分离原则,输入、输出和结果处理都混杂在一个对象里面,会存在回调嵌套问题。Fetch API 作为XHR的替代者,具备更加强大的能力,它致力于向前端引入和HTTP协议的Request/Response同样的原语,它是一个面向未来的API,既现代又底层,有很多非常优雅的特性,Promise-based,Request/Response primitives,Support Streams,等等。
# Cache
HTML5提供了一种Application Cache机制,使得基于web的应用程序可以离线运行,所有现代浏览器都支持Application Cache机制,这是非常罕见的,也可见浏览器厂商对离线能力是多么的重视。但Application Cache机制也存在诸多缺陷,导致它最终只能成为HTML5规范的non-normative特性。ServiceWorker 里面的Cache API 提供了精细的存储控制能力,Fetch+Cache已能较好的替代Application Cache。
# Push
PWA官网 描述了它具备的三个核心特性,Reliable,Fast,Engaging。他们把可靠放在非常重要的位置,可靠性也是Web与Native差别最大的方面之一。比如,用户关闭了页面,就很难让用户再回到原来的页面,而Push API给前端开放了消息推送的能力,灵活使用Push能力可以极大的提升Web应用的可靠性。国家工信部也明确要求各手机厂商统一PUSH标准,可以看到政府和业界对PUSH能力都非常看重。
# Add to Home Screen
Web应用与Native应用,在表现形式上的最大区别是,Native应用可以在手机屏幕上建立图标,在系统设置列表里面有相应的列表项。在Android系统,这个区别已经成为过去,Android系统允许PWA应用建立桌面图标,甚至可以为PWA应用生成APK真实安装到系统里,与Native应用表现一致。
# ServiceWorker
PWA的关键技术是ServiceWorker。SW有一些重要的特性,它是事件驱动的Worker,具有与文档无关的生命周期,可以拦截注册Scope下的所有请求和响应,具有Reliable的能力。 (1)事件驱动,是指Web引擎(浏览器内核)收到事件会触发SW线程启动。 那么,收到事件,为什么SW线程必须启动呢?因为事件处理的代码是运行在sw.js(SW注册时指定的脚本),而sw.js是运行在SW线程。举个例子,Web引擎收到install事件,会启动SW线程,SW线程在初始化时会执行sw.js,前端可以在sw.js监听install事件,install事件触发时事件处理函数就会执行,这就是事件驱动的过程。理解事件驱动,是理解SW很多特性的基础,比如页面文档未关闭,SW线程为什么会关闭。
为什么SW是事件驱动的,而不是常驻内存的呢?事件驱动,除了收到事件SW线程要启动,也意味着事件处理完成,SW线程是需要关闭的。SW有独立的GlobalScope,独立的Isolate,独立的JS运行环境,SW线程的资源消耗是非常大的,事件驱动是减少SW线程资源消耗的一种有效的方式,这就是SW被设计成事件驱动的原因。 (2)SW具有与文档无关的生命周期。 通常,Web页面的生命周期非常依赖文档,文档持有大量关键对象,例如Parser解析器,Loader加载器,JS控制器。页面通过这些对象去使用网络和使用JS引擎执行JS。页面关闭时,这些关联对象会析构,页面无法再执行JS。而SW线程有独立的JS引擎实例,有独立的JS运行环境,可以独立执行JS,不需要依赖页面文档的环境。页面关闭时,页面的JS执行环境就销毁了,但SW的JS环境不受影响,可以继续执行JS。 SW的生命周期包含两部分,一部分是SW线程,另外一部分是SW脚本。SW脚本的状态是存储在数据库的,打开页面时,会先从数据库中读取当前页面activated状态的SW脚本,然后再派发Fetch事件去启动SW线程。SW要控制页面,脚本是activated状态,线程是Running状态,两者缺一不可,而这两者的生命周期都与页面文档无关。这就是SW文档无关生命周期的内在涵义。
SW线程启动后,处于Running状态,sw js的代码就可以被执行。如果仅仅期望sw js代码被执行,那么SW线程Running就可以了,SW脚本不一定要处于Activated状态。SW脚本处于Activated状态,页面Fetch请求就会受它控制,由它决定请求是走SW还是走网络。SW控制页面请求的过程是这样的,SW脚本激活之后会存储相关信息到LevelDB数据库,再次访问页面时,可以直接从注册数据库里读取信息,然后派发Fetch事件去启动SW线程,SW线程启动完成之后,所有的Fetch请求都会触发fetch事件,前端可以监听fetch事件,按照各种策略去获取资源。 (3)SW可以拦截注册Scope下所有的请求和响应。 SW控制的页面,所有的请求,都会经过SW,由内部对象负责处理。内部对象会检查资源是否在SW缓存,如果在SW缓存,就会创建读取缓存的任务,直接从SW缓存读取;如果不在SW缓存,就会创建写入缓存的任务,继续走到网络流程,并将结果写入SW缓存。如果请求不受SW控制,会直接进入网络请求,走正常请求的流程。 (4)SW具有Reliable的能力。 Web通常是不可靠的,网络不可靠,用户停留时间不可靠。PWA要解决的问题就是提供可靠的Web服务。SW是实现Reliable的关键技术。SW为什么可以提供可靠的Web服务呢? 前端可使用SW缓存,精细控制每个资源的缓存,让资源缓存更可靠;前端可以使用Push预加载,让Web应用能更可靠的获取到资源;前端可以使用Background Sync,触发后台更新资源;前端可以使用Background Fetch,后台上传或下载大文件;也就是说,前端可以使用SW相关的一系列技术,让Web在特殊场景下依然能提供非常可靠的服务。
# 总结
今天,我们为大家分享了PWA技术。Google推出这项技术的背景,解决什么样的问题,PWA技术的构成,我们花了较大篇幅来介绍PWA的关键技术ServiceWorker。明天,我们将会介绍PWA技术在阿里体系内的落地情况及影响。欢迎大家关注。