PWA初探整理

關鍵特性

  • Web App Manifest – 在主屏幕添加app圖標,定義手機標題欄顏色之類
  • App Shell – 先顯示APP的主結構,再填充主數據,更快顯示更好體驗
  • Service Worker - 緩存,離線開發,以及地理位置信息處理等
  • Push Notifion - 消息推送

Service Worker

運行在瀏覽器端的代理服務器

clipboard.png

基本特色

  • 事件驅動型服務線程
  • 只能基於https或者localhost
  • 能夠控制頁面所發送網絡請求的處理方式
  • 運行在瀏覽器後臺的腳本,沒法直接操做dom

生命週期

clipboard.png

支持事件

clipboard.png

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 接手html

sw.js發生了更新,可是頁面一直掛載中,沒有關閉或強制刷新,此時上一個版本的sw還在工做中,新的sw處於等待中git

// 安裝階段跳過等待,直接進入 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做爲紐帶github

// 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

建立一個cachejson

cache.add/addAll

  • 支持傳入Requesturl
  • 緩存資源,支持單個和數組
  • 在cache.add內部會自動去調用fetch取回request的請求結果,而後纔是把response存入cache

cache.put

  • 至關於cache.add的第二步,即fetch到response後存入cache
  • 沒法直接緩存跨域的請求,response.status會返回0segmentfault

    • 若是跨域的資源支持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

clipboard.png

  • 詢問受權
  • 發送subscription給後端存儲
  • 服務端向FCM/GCM發送消息,同時帶上subscription
  • FCM根據subscription再下發給對應的瀏覽器
  • 觸發Service Worker的push事件
  • 後續處理

參考

相關文章
相關標籤/搜索