Appearance
逐渐建立用户和应用的连接,响应式设计,适应低质量网络,像原生应用一样使用,便于更新,只使用 HTTPS,搜索引擎能搜到,推送,桌面快捷方式,通过 URL 连接...
特点
- Progressive - 逐渐建立用户和应用的连接
- Responsive - 响应式设计
- Connectivity independent - 适应低质量网络
- App-like - 像原生应用一样使用
- Fresh - 便于更新
- Safe - 只使用 HTTPS
- Discoverable - 搜索引擎能搜到
- Re-engageable - 推送
- Installable - 桌面快捷方式
- Linkable - 通过 URL 连接
目的
- 使用 app shell 方式创建应用
- 使你的应用能离线工作
- 为你的离线应用存储数据
App Shell
什么是 app shell
app shell 包含最基础的 HTML, CSS 和 JS,用户在第一次访问 PWA 的时候加载一次就缓存在本地,以后在打开 PWA 就能从本地直接加载 app shell 然后再从网络加载数据渲染包含内容的 UI。
app shell 包含什么
- 打开 PWA 时需要马上显示的东西
- 关键的 UI 组件
- app shell 需要的图片、样式、脚本资源
Service worker
什么是 service worker
service worker 是一段跑在浏览器后台线程的脚本,可用于拦截作用域下的请求,从而直接返回缓存的数据。实现离线使用的目的!
什么是 fetch
fetch 是新一代的 AJAX API,用于替代 XmlHttpRequest
安装
目前 Chrome 和 Firefox 可直接使用。service worker 是有作用域的,一般都把 service-worker.js
文件放在根目录下,这样可拦截所有请求。
js
if ('serviceWorker' in navigator) {
navigator.serviceWorker
.register('./service-worker.js')
.then(function () {
console.log('Service Worker Registered');
});
}
缓存策略
- 有缓存直接返回缓存,没缓存再从网络获取再返回数据
- 不管有没有,先返回缓存,然后从网络获取数据,根据更新时间决定是否更新 UI
缓存 app shell
首次打开时缓存静态文件
⚠️ cache.addAll()
是链式的,也就是说前面有请求出错,后面的请求都会中断。
js
const cacheName = 'app-shell-v1';
const filesToCache = ['files to cache'];
self.addEventListener('install', function (e) {
e.waitUntil(
caches.open(cacheName).then(function (cache) {
return cache.addAll(filesToCache);
});
);
});
拦截请求
这段拦截代码目标是静态文件,使用缓存策略2。
js
self.addEventListener('fetch', function (e) {
e.respondWith(
caches.match(e.request).then(function (response) {
return response || fetch(e.request);
})
);
});
删除过时缓存
每次打开 PWA 都会触发这个事件,根据 cacheName 来判断是否过时。
js
self.addEventListener('activate', function (e) {
e.waitUntil(
caches.keys().then(function (keyList) {
return Promise.all(keyList.map(function (key) {
if (key !== cacheName && key !== dataCacheName) {
console.log('[ServiceWorker] Removing old cache', key);
return caches.delete(key);
}
}));
})
);
return self.clients.claim();
});
缓存数据
js
self.addEventListener('fetch', function (e) {
var dataUrl = '/api/v1';
if (e.request.url.indexOf(dataUrl) > -1) {
e.respondWith(
caches.open(dataCacheName).then(function (cache) {
return fetch(e.request).then(function (response) {
cache.put(e.request.url, response.clone());
return response;
});
});
);
}
});
获取缓存的数据
js
if ('caches' in window) {
caches.match(url).then(function (response) {
if (response) {
response.json().then(function (json) {
console.log(json);
});
}
});
}
原生应用集成
只需要添加一个 manifest.json 文件来宣告应用的详情,Chrome 会自动根据是否使用了 service worker, 是否开启了 SSL 加密以及访问频率来决定是否显示添加到桌面的快捷方式条。
json
{
"name": "Weather",
"short_name": "Weather",
"icons": [{
"src": "images/icons/icon-256x256.png",
"sizes": "256x256",
"type": "image/png"
}],
"start_url": "/index.html",
"display": "standalone",
"background_color": "#3E4EB8",
"theme_color": "#2F3BA2"
}
html
<link rel="manifest" href="/manifest.json">