1

PWA是什么?

Progressive Web Apps (PWA)是Google在移动时代力推的一个提升webapp性能和体验解决方案,官方列举了几大新特点:

  • 渐进式 - 适用于所有浏览器,因为它是以渐进式增强作为宗旨开发的

— 连接无关性 - 能够借助 Service Worker 在离线或者网络较差的情况下正常访问

  • 类似应用 - 由于是在 App Shell 模型基础上开发,因为应具有 Native App 的交互和导航,给用户 Native App 的体验
  • 持续更新 - 始终是最新的,无版本和更新问题
  • 安全 - 通过 HTTPS 协议提供服务,防止窥探和确保内容不被篡改
  • 可索引 - 应用清单文件和 Service Worker 可以让搜索引擎索引到,从而将其识别为『应用』
  • 粘性 - 通过推送离线通知等,可以让用户回流
  • 可安装 - 用户可以添加常用的 webapp 到桌面,免去去应用商店下载的麻烦
  • 可链接 - 通过链接即可分享内容,无需下载安装

个人理解核心目的增强WebApp的体验:

  • 站点可添加至主屏幕(强提示),缩短操作路径
  • 使用 App Shell模型,应用达到秒开效果
  • 全屏方式运行
  • 支持离线缓存
  • 消息推送

核心技术

Service Worker

Service Worker是实现PWA应用最重要的一项技术,是一个在用户没有打开网页没有交互行为时运行在浏览器后台进程中的脚本,提供管理资源缓存、拦截资源、消息推送通知请求等功能。
阅读下面内容前你需要做一些预备知识

Service_Worker_API
Cache_API

首先我们需要检查浏览器是否支持service worker

if ('serviceWorker' in navigator) {
    navigator.serviceWorker
             .register('./service-worker.js')
             .then(function() { console.log('Service Worker Registered'); });
  }

注意service-worker.js文件应用的根文件夹内,因为服务工作线程的作用域由该文件所在的目录定义。
在service worker中,我们通过cache相关的api缓存静态资源或者请求数据,从而达到应用秒开的效果。

首先,我们在service worker被install之后,通过 caches.open() 打开一个指定key的缓存。缓存key可让我们对资源进行版本控制。实际使用时,我们一般会将数据与 App Shell(静态资源) 分开,以便我们能轻松地更新某个数据,而不会影响其他数据。

缓存打开后,我们便可调用 cache.addAll(),这个带有网址列表参数的方法随即从服务器获取文件,并将响应添加到缓存内。遗憾的是,cache.addAll() 具有原子性,如果任何一个文件失败,整个缓存步骤也将失败!

var cacheName = 'cache-1';
var filesToCache = [
    '/scripts/app.js',
    '/styles/inline.css',
    '/images/clear.png',
];

self.addEventListener('install', function(e) {
  console.log('[ServiceWorker] Install');
  e.waitUntil(
    caches.open(cacheName).then(function(cache) {
      console.log('[ServiceWorker] Caching app shell');
      return cache.addAll(filesToCache);
    })
  );
});

重新加载页面之后,打开 DevTools,转至 Application 面板的 Cache Storage 窗格,可以查看所有被缓存的资源
image.png

上面提到缓存分为静态资源和请求数据。在访问页面时,我们拦截发送的请求,并将其响应存储在缓存内。对于静态资源我们再次访问页面时,如果资源版本没有修改,就可以直接命中缓存方便。而对于请求的数据我们采用缓存优先于网络策略,我们期望网络响应成为“可信来源”,始终能够为我们提供最新信息。在第一次访问页面时,缓存数据解决了webapp内容区域空窗的问题,让用户体验更好。

self.addEventListener('fetch', function(e) {
  // console.log('[Service Worker] Fetch', e.request.url);
  var dataUrl = 'https://query.yahooapis.com/v1/public/yql';
  if (e.request.url.indexOf(dataUrl) > -1) {
    /*
     * When the request URL contains dataUrl, the app is asking for fresh
     * weather data. In this case, the service worker always goes to the
     * network and then caches the response. This is called the "Cache then
     * network" strategy:
     * https://jakearchibald.com/2014/offline-cookbook/#cache-then-network
     */
    e.respondWith(
      caches.open(dataCacheName).then(function(cache) {
        console.log('dataCacheName', cache)
        return fetch(e.request).then(function(response){
          cache.put(e.request.url, response.clone());
          return response;
        });
      })
    );
  } else {
    /*
     * The app is asking for app shell files. In this scenario the app uses the
     * "Cache, falling back to the network" offline strategy:
     * https://jakearchibald.com/2014/offline-cookbook/#cache-falling-back-to-network
     */
    e.respondWith(
      caches.match(e.request).then(function(response) {
        return response || fetch(e.request);
      })
    );
  }
});

对于缓存,它是一把双刃剑,它带来了出色体验,也会面临一些新的难题-缓存更新。在生产环境中,google官方推荐sw-precache生成service worker代码,它内置了缓存更新策略,可以确保将资源过期的请求发送到服务器。

App Shell

App Shell 是启动PWA应用用户界面所需的最小的资源(HTML、CSS 和 JavaScript)。Shell文件一旦通过网络完成加载,就会通过service workder保存到缓存中。以后每当用户打开应用时,就会自动从本地的缓存中打开Shell文件,确保加载速度非常快。
image.png

Add To Home Screen

PWA应用允许用户将轻松得将使用的webapp添加到系统的主屏幕,而且这个功能实现十分简单,浏览器内核帮我们处理了大量复杂的内部工作,我们只需要在应用根目录下添加一个应用清单文件manifest.json
供参考的模板

{
  "name": "Weather",
  "short_name": "Weather",
  "icons": [{
    "src": "images/icons/icon-128x128.png",
      "sizes": "128x128",
      "type": "image/png"
    }, {
      "src": "images/icons/icon-144x144.png",
      "sizes": "144x144",
      "type": "image/png"
    }, {
      "src": "images/icons/icon-152x152.png",
      "sizes": "152x152",
      "type": "image/png"
    }, {
      "src": "images/icons/icon-192x192.png",
      "sizes": "192x192",
      "type": "image/png"
    }, {
      "src": "images/icons/icon-256x256.png",
      "sizes": "256x256",
      "type": "image/png"
    }],
  "start_url": "/index.html",
  "display": "standalone",
  "background_color": "#3E4EB8",
  "theme_color": "#2F3BA2"
}

manifest.json可以描述webapp不同的展现形式

  • 以全屏模式启动
  • 控制屏幕方向以获得最佳查看效果
  • 定义网站的“启动画面”启动体验和主题颜色
  • 追踪您是从主屏幕还是从网址栏启动

兼容性

当我们提PWA应用兼容性问题时,我们说的其实是PWA背后的新特性在各大浏览器厂商的支持程度。

在当前时间点来看这个问题,总体还是抱乐观态度,国内外的大部分浏览器都已经实现PWA必需的关键技术,所有剩余技术目前都处于开发阶段。

对于最大的绊脚石safari,苹果也2018年1月宣布将在 iOS 11.3 和 macOS 10.13.4 版本上正式增加对 Service Worker 的支持,同时还支持了添加到桌面(Web App Manfiest)。

兼容性参考,数据每两周更新一次

最后

行业内flipboardflipkart阿里巴巴国际站饿了么都已经落地PWA,百度开源了基于Vue的PWA解决方案lavas。PWA应用正在将迎来春天,成为趋势。
对PWA感兴趣的同学可以一起探讨学习


amibug
440 声望8 粉丝

前端菜鸟一枚


引用和评论

0 条评论