關鍵特性
- Web App Manifest – 在主屏幕添加app圖標,定義手機標題欄顏色之類
- App Shell – 先顯示APP的主結構,再填充主數據,更快顯示更好體驗
- Service Worker - 緩存,離線開發,以及地理位置信息處理等
- Push Notifion - 消息推送
Service Worker
運行在瀏覽器端的代理服務器
基本特點
- 事件驅動型服務線程
- 只能基於https或者localhost
- 可以控制頁面所發送網絡請求的處理方式
- 運行在瀏覽器後臺的腳本,無法直接操作dom
生命週期
支持事件
register
- 在主線程代碼中註冊
- 可以指定scope,通常指定到網站根路徑,能夠攔截所有的fetch事件
- service worker 已經被註冊過,瀏覽器會自動忽略上面的代碼
if ('serviceWorker' in navigator) {
window.addEventListener('load', function () {
navigator.serviceWorker.register('/sw.js', {
scope: '/'
}).then(function (reg) {
// 註冊成功
console.log('success and scope: ', reg.scope);
}).catch(function (err) {
// 註冊失敗
console.log('failed: ', err);
});
});
}
installing
緩存文件
installed/waiting
此狀態下,worker有效但尚未激活,它尚未納入 document的控制,確切來說是在等待着從當前 worker 接手
sw.js發生了更新,但是頁面一直掛載中,沒有關閉或強制刷新,此時上一個版本的sw還在工作中,新的sw處於等待中
// 安裝階段跳過等待,直接進入 active
self.addEventListener('install', function (event) {
event.waitUntil(self.skipWaiting());
});
self.addEventListener('activate', function (event) {
event.waitUntil(
Promise.all([
// 更新客戶端
self.clients.claim()
])
);
});
activating/activated
緩存更新
fetch
代理請求
message
sw與主線程間的雙向通信,建立MessageChannel
作爲紐帶
// index.html
navigator.serviceWorker.register('/service-worker.js', {
scope: '/'
}).then(function (reg) {
// 創建一個
const channel = new MessageChannel();
// port1供主線程使用
channel.port1.onmessage = messageEvent => {
console.log('來自sw的message', messageEvent.data);
}
const serviceWorker = reg.active;
// port2指向sw
if (serviceWorker) {
serviceWorker.postMessage('index->sw', [channel.port2]);
}
});
// sw.js
self.addEventListener('message', function (event) {
console.log('來自index的message', event.data);
// 通過port找到發送消息的client
event.ports[0].postMessage('sw->index');
});
更多的應用場景
- 後臺數據同步
- 預取用戶可能需要的資源,比如相冊中的後面數張圖片
- 在後臺集中接收計算成本高的數據更新,比如地理位置和陀螺儀信息,多個頁面就可以利用同一組數據
Cache API
- 只能緩存 GET 請求;
- 可以緩存屬於自己域下的請求,同時也可以緩存跨域的請求,不過無法對跨域請求的Request和Response進行修改
- 緩存的更新需要自行實現
- 緩存不會過期,除非將手動刪除,大小有限制,LRU刪除
caches.open
創建一個cache
cache.add/addAll
- 支持傳入Requesturl
- 緩存資源,支持單個和數組
- 在cache.add內部會自動去調用fetch取回request的請求結果,然後纔是把response存入cache
cache.put
- 相當於cache.add的第二步,即fetch到response後存入cache
-
無法直接緩存跨域的請求,response.status會返回0
- 如果跨域的資源支持CORS,那麼可以把request的mod改成cors
caches.match
catch.match(request, {
}).then(function(response) {
})
cache.delete
一些使用點
-
分段緩存,提高安裝成功率
- 先安裝非重要資源,再安裝重要資源
-
漸進式緩存
- 對於在install時沒有緩存的資源,可以在用戶交互之後再緩存
-
優先原則
- 對於靜態頁面,緩存優先,減少請求
- 對於天氣類型應用,先去fetch,服務器故障或者網絡不良時,折回本地緩存
Manifest
一個基本的manifest.json
{
"short_name": "短名稱",
"name": "這是一個完整名稱",
"icon": [
{
"src": "icon.png",
"type": "image/png",
"sizes": "48x48"
}
],
"start_url": "index.html"
}
可以實現的功能
-
基本功能
- 自定義名稱
- 自定義圖標
- 設置啓動網址
- 設置作用域
-
添加啓動畫面
- 設置顯示類型
- 指定顯示方向
- 設置主題色
-
應用安裝橫幅
-
站點部署 manifest.json,該文件需配置如下屬性:
- short_name (用於主屏幕顯示)
- name (用於安裝橫幅顯示)
- icons (其中必須包含一個 mime 類型爲 image/png 的圖標聲明)
- start_url (應用啓動地址)
- display (必須爲 standalone 或 fullscreen)
- 站點註冊 Service Worker。
- 站點支持 HTTPS 訪問。
- 站點在同一瀏覽器中被訪問至少兩次,兩次訪問間隔至少爲 5 分鐘。
-
Web Push
Notification
PushManager
- 詢問授權
- 發送subscription給後端存儲
- 服務端向FCM/GCM發送消息,同時帶上subscription
- FCM根據subscription再下發給對應的瀏覽器
- 觸發Service Worker的push事件
- 後續處理
參考
- https://segmentfault.com/a/11...
- https://x5.tencent.com/tbs/gu...
- https://lavas.baidu.com/pwa/o...
- http://www.zhangxinxu.com/wor...
- https://zhuanlan.zhihu.com/p/...
- https://github.com/delapuente...
- https://github.com/SangKa/PWA...
- 使用Service Worker發送Push推送
- https://fed.renren.com/2017/1...
- https://pwa.rocks/