PWA的探索與應用

本文由雲+社區發表html

PWA(Progressive Web App)起源背景

傳統的Web網頁存在如下幾個問題:web

  • 進入一個頁面必需要記住它的url或者加入書籤,入口不便捷;
  • 沒網絡就沒響應,不具有離線能力;
  • 不像APP同樣能進行消息推送。

Native app:chrome

  • 開發成本高
  • 軟件上線須要審覈
  • 即便使用頻率不高,想使用一個app必須先下載安裝

PWA概念的提出

2016 年Google I/O 大會上提出一個 Next Web Generation 的概念。PWA是在傳統Web應用的基礎上,結合Manifest和service worker,完善Web應用的一些能力,好比:json

  • 添加至主屏幕,點擊主屏幕圖標能夠實現啓動動畫以及隱藏地址欄
  • 實現離線緩存功能,即便用戶手機沒有網絡,依然可使用一些離線功能
  • 消息推送

PWA技術點

Web App Manifest

Web App Manifest 技術實現了將PWA網頁應用 添加至桌面的功能,但該項技術目前仍處於實驗性階段,各瀏覽器支持度不高小程序

imgimage.pngsegmentfault

PWA 站點部署的 manifest.json文件知足如下條件時會自動顯示橫幅:微信小程序

- short\\_name (主屏幕顯示)
- name (安裝橫幅顯示)
- icons (必須包含一個 mime 類型爲 image/png 的圖標聲明)
- start\\_url (應用啓動地址)
- display (必須爲 standalone 或 fullscreen)
- 站點註冊 Service Worker。
- 站點支持 HTTPS 訪問。
- 同一瀏覽器中站點至少被訪問兩次,間隔至少爲 5 分鐘。

Service Worker

​ PWA應用的離線體驗、按期的後臺同步以及推送通知等功能的實現依賴於Service Worker技術,下圖爲目前SW技術的支持度。瀏覽器

img

SW具備如下特徵:緩存

  • 一個獨立的 worker 線程,獨立於當前網頁進程,有本身獨立的 worker context。
  • 一旦被 install,就永遠存在,除非被手動 unregister
  • 用到的時候能夠直接喚醒,不用的時候自動睡眠
  • 離線內容開發者可控
  • 能向客戶端推送消息
  • 不能直接操做 DOM
  • 必須在 HTTPS 環境下才能工做
  • 異步實現,內部大都是經過 Promise 實現

Service Worker生命週期

img

  • installing:這個狀態發生在 SW 註冊以後開始安裝,install 事件回調中執行skipWaiting()方法表示強制當前處在 waiting 狀態的 Service Worker 進入 activate 狀態。
  • installed:SW已經完成了安裝,等待其餘的 SW 線程被關閉。
  • activating:在這個狀態下清除其餘的worker 以及關聯緩存的舊緩存資源,等待新的 SW線程被激活。在 activate 事件回調中執行self.clients.claim()方法表示取得頁面的控制權, 這樣以後打開頁面都會使用版本更新的緩存。舊的 Service Worker 腳本再也不控制着頁面,以後會被中止。
  • activated:在這個狀態能夠處理功能性的事件 fetch (請求)、sync (後臺同步)、push (推送)。
  • 廢棄狀態 ( redundant ):這個狀態表示一個 Service Worker 的生命週期結束。

Service Worker 支持的事件

img

  • install:Service Worker 安裝成功後被觸發的事件, 在事件處理函數中能夠添加須要緩存的文件
  • activate:當 Service Worker 安裝完成後並進入激活狀態,會觸發 activate 事件。經過監聽 activate 事件你能夠作一些預處理,如對舊版本的更新、對無用緩存的清理等。
  • message:Service Worker 運行於獨立 context 中,沒法直接訪問當前頁面主線程的 DOM 等信息,可是經過 postMessage API,能夠實現他們之間的消息傳遞,這樣主線程就能夠接受 Service Worker 的指令操做 DOM。
  • fetch :當瀏覽器在當前指定的 scope 下發起請求時,會觸發 fetch 事件,並獲得傳有 response 參數的回調函數。fetch 事件特別重要,由於它可以定義你的緩存策略。也就是說,你能夠決定什麼時候使用緩存數據,什麼時候使用網絡請求來的數據。
  • push:push 事件是爲推送準備的。經過 PUSH API,當訂閱了推送服務後,可使用推送方式喚醒 Service Worker 以響應來自系統消息傳遞服務的消息,即便用戶已經關閉了頁面。
  • sync:sync 事件由 background sync (後臺同步)發出。background sync 是 Google 配合 SW 推出的 API,用於爲 Service Worker 提供一個能夠實現註冊和監聽同步處理的方法。但它還不在 W3C Web API 標準中。在 Chrome 中這也只是一個實驗性功能,須要訪問 chrome://flags/#enable-experimental-web-platform-features ,開啓該功能,而後重啓生效。Sync 事件容許延遲網絡任務,直到用戶鏈接上網絡,它實現的功能一般被稱爲後臺同步。這對於在離線模式下,確保用戶啓動的任何有網絡依賴的任務,最終都將在網絡再次可用時達到其預期目的,是很是有用的。

Service Worker 的工做原理

Service Worker是基於註冊、安裝、激活等步驟微信

註冊

if ('serviceWorker' in navigator) {
window.addEventListener('load', function () {
    navigator.serviceWorker.register('/jslearning/sw.js') // 默認做用域爲jslearning下,也能夠經過設置scope參數進行設置
        .then(function (registration) {
            // 註冊成功
            console.log('ServiceWorker registration successful with scope: ', registration.scope);
        })
        .catch(function (err) {
            // 註冊失敗:(
            console.log('ServiceWorker registration failed: ', err);
        });
});
}

安裝

this.addEventListener('install', function(event) {
  console.log('V1 installing…');
  //須要緩存的重要的高優先級資源
  var vipUrlsToPrefetch = [
'./index.html'
  ];
  //次重要的資源
  var urlsToPrefetch = [
'./icon.png'
  ];
  event.waitUntil(
caches.open(OFFLINE_CACHE_NAME).then(function(cache) {
  //urlsToPrefetch非重要資源,即便有資源加載失敗也不影響Service Worker安裝
  cache.addAll(urlsToPrefetch);
  //vipUrlsToPrefetch中資源所有請求成功,Service Worker安裝事件才順利完成,能夠進入激活事件
  return cache.addAll(vipUrlsToPrefetch);
})
  );      
});

激活

//Service Worker激活事件
this.addEventListener('activate', function(event) {
  //在激活事件中清除非當前版本的緩存避免用戶存儲空間急劇膨脹
  event.waitUntil(caches.keys().then(function(cacheNames) {
console.log('V1 activate');
return Promise.all(cacheNames.map(function(cacheName) {
    if (cacheName !== OFFLINE_CACHE_NAME) {
      if(cacheName.indexOf(OFFLINE_CACHE_PREFIX) != -1) {
        return caches.delete(cacheName);
      }
    }
}));
  }));
});

Service Worker更新

  • 若是線程的字節與已有的SW線程字節不一樣,瀏覽器則考慮更新SW線程。
  • 更新的SW線程與現有SW線程一塊兒啓動,並獲取本身的 install 事件。
  • 若是新工做SW線程出現不正常狀態代碼(例如,404)、解析失敗,在執行中引起錯誤或在安裝期間被拒,則系統將捨棄新工做線程,但當前工做線程仍處於活動狀態。
  • 安裝成功後,更新的工做線程將 wait,直到現有工做線程控制0個客戶端。
  • self.skipWaiting() 可跳過等待狀況,這意味着sw線程在安裝完後當即激活。

Service Worker緩存策略

​ Service Worker緩存策略大部分在fetch與install時間中定義,對於某些固定不變的靜態資源,能夠在Service Worker初次安裝的install事件中將其緩存,但資源過大或者網絡不佳都會形成資源並未所有下載成功而致使Service Worker安裝被中斷安裝失敗。SW主要有如下幾類緩存策略:

  • 不影響安裝的資源預緩存
  • 漸進式緩存
  • 僅使用緩存、僅使用網絡
  • 緩存優先 、網絡優先
// 漸進式緩存
var addToCache = function(req) {   
  return fetch(req.clone()).then(function(resp) {   
    var cacheResp = resp.clone();
    if (!resp.ok) {
      return resp;
    }
    caches.open(OFFLINE_CACHE_NAME).then(function(cache) {
      cache.put(req.clone(), cacheResp);
    });
    return resp;
  });
};
 
this.addEventListener('fetch', function(event)  {
  event.respondWith(
     caches.open(OFFLINE_CACHE_NAME).then(function(cache) {
          return cache.match(event.request);
      }).then(function(response) {
        if (response) {
            return response;
        } else {
            return addToCache(event.request);
        }
    })
  ); 
});

PWA應用能夠經過開發者工具中的Application進行查看調試,以下圖所示:

img

PWA優缺點總結

優勢

  • 能夠將app的快捷方式放置到桌面上,全屏運行,與原生app無異
  • 可以在網絡差和斷網條件下
  • 推送消息的能力
  • 快速響應用戶指令

缺點

  • 支持率不高
  • Chrome在安卓移動端上的佔有率很低
  • 依賴的GCM服務在國內沒法使用
  • 微信小程序的競爭

PWA應用

  • Lavas 是一套基於 Vue 的 PWA 解決方案,可以幫助開發者快速搭建 PWA 應用
  • 新浪微博
  • 餓了麼
  • Instagram
  • Twitter
  • Offline Wikipedia
  • Spotlight
  • ...

參考文獻

此文已由做者受權騰訊雲+社區在各渠道發佈

獲取更多新鮮技術乾貨,能夠關注咱們騰訊雲技術社區-雲加社區官方號及知乎機構號

相關文章
相關標籤/搜索