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

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

clipboard.png

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

參考

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章