渐进式 Web 应用(Progressive Web Apps,也被称为 PWAs)是 Web 技术方面一项令人兴奋的创新。PWA 混合了多项技术,能够让 Web 应用的功能类似于原生移动应用。它为开发人员和用户带来的收益能够突破纯 Web 解决方案和纯原生解决方案的限制:
-
你只需要一个按照开放、标准 W3C Web 技术开发的应用,不需要开发单独的原生代码库;
-
用户在安装之前就能发现并尝试你的应用;
-
没有必要使用 AppStore,无需遵循复杂的规则或支付费用。应用程序会自动更新,无需用户交互;
-
用户会被提示“安装”,这样会添加一个图标到主屏幕上;
-
当启动的时候,PWA 会展现一个有吸引力的启动画面;
-
如果需要的话,浏览器的 chrome 选项可以进行修改,以便于提供全屏的体验;
-
基本文件会在本地缓存,所以 PWA 要比标准 Web 应用反应更快(它们甚至能够比原生应用更快);
-
安装是轻量级的,可能只需几 KB 的缓存数据;
-
所有的数据交换必须要通过安全的 HTTPS 连接来执行;
-
PWA 支持离线功能,当网络恢复后,数据会进行同步。
service worker 本意为渐进式网络应用(progressive web app, PWA)提供离线支持,使得网络应用可以离线运行。一旦启用 service worker ,则它可以根据开发者的缓存配置为用户缓存网站静态与动态资源,并截获用户的所有网络请求,并根据缓存配置来决定是从缓存还是网络获取相应资源,从而可以提高网页的加载速度。测试结果表明,一般能实现 4-5 倍的加速,最好的时候能够实现 10 倍的加速。使用 service worker 实现网站加速的优势有:
- 可以很轻易地实现静态与动态资源缓存,决定缓存空间的大小与缓存时间期限,可定制性高;
- 不需要服务端支持,只需要在本地生成 service worker 文件并上传就可以使用,特别适用于没有服务端的静态博客或网站;
- 配合 sw-precache ,只需要做好缓存配置, sw-precache 可以自动生成 service woker 文件,不需要自己实现缓存逻辑;
- 可以灵活为动态与静态资源,以及不同网址提供不同的缓存机制,并实现资源的动态更新,同样不需要自己编写代码
- 后台消息传递
- 网络代理,转发请求,伪造响应
- 离线缓存
- 消息推送
- … …
const self = this;
const HOST_NAME = location.host;
const VERSION_NAME = 'CACHE-v5';
const CACHE_NAME = HOST_NAME + '-' + VERSION_NAME;
const CACHE_HOST = [HOST_NAME, '0.plus', 'icms.biyong.io'];
var cacheList = [ "./css/common.css", "./css/discover.css", "discover.html", ] const onInstall = function (event) { console.log('触发install事件--------'); // 打开一个缓存空间,将相关需要缓存的资源添加到缓存里面 event.waitUntil( caches .open(CACHE_NAME) .then(function (cache) { self.skipWaiting(); console.log('Install success---------------'); return cache.addAll(cacheList) }) ); }; // 当浏览器解析完sw文件时,serviceworker内部触发install事件 self.addEventListener('install', onInstall);
- 在新的ServiceWorker线程代码里,使用了self.skipWaiting()
- 或者当用户导航到别的网页,因此释放了旧的ServiceWorker时候
- 或者指定的时间过去后,释放了之前的ServiceWorker
const onActive = function (event) { event.waitUntil( caches .keys() .then(function (cacheNames) { return Promise.all( cacheNames.map(function (cacheName) { // active事件中通常做一些过期资源释放的工作 if (CACHE_NAME.indexOf(cacheName) === -1) { return caches.delete(cacheName); } }) ); }) .then(function () { console.log('active claim success 2-------------'); self.clients.claim(); }) ); }; // 如果当前浏览器没有激活的service worker或者已经激活的worker被解雇, // 新的service worker进入active事件 self.addEventListener('activate', onActive);
const onFetch = function (event) { event.respondWith(handleFetchRequest(event.request)); }; const handleFetchRequest = function (req) { const request = req; if (isCORSRequest(req.url, HOST_NAME)) { const request = new Request(req.url, {mode: 'no-cors'}); } return caches.match(request) .then(function (response) { if (response) { return response; } else { console.log('缓存没找到' + request.url); } }) const request = req; if (isCORSRequest(req.url, HOST_NAME)) { const request = new Request(req.url, {mode: 'no-cors'}); } return fetch(request) .then(function (response) { console.log(request.url + '请求回来了'); // online: Return the response if need if (isNeedCache(req) && isValidResponse(response)) { const clonedResponse = response.clone(); caches .open(CACHE_NAME) .then(function (cache) { cache.put(request, clonedResponse); console.log('添加缓存: ' + request.url); }) } return response; }) .catch(error => { // offline: Return the caches console.log('fetch ' + request.url + ' fail: ' + error.message); return caches.match(request) .then(function (response) { if (response) { return response; } else { console.log('缓存没找到' + request.url); } }) }) }; self.addEventListener('fetch', onFetch);
npm install sw-precache
来进行安装。sw-precache可以配合多个工具使用,这里我主要介绍一下如何配合gulp来使用。