使用 Service Workers 來預緩衝應用外殼

來源:互聯網
上載者:User

標籤:png   多個   事件監聽器   ddb   項目   tin   通過   學習   建立   

Progressive Web Apps 是快速且可安裝的,這意味著它能在線上、離線、斷斷續續或者緩慢的網路環境下使用。為了實現這個目標,我們需要使用一個 service worker 來緩衝應用外殼,以保證它能始終迅速可用且可靠。

如果你對 service workers 不熟悉,你可以通過閱讀 介紹 Service Workers 來瞭解關於它能做什麼,它的生命週期是如何工作的等等知識。

service workers 提供的是一種應該被理解為漸進增強特性,這些特性僅僅作用於支援service workers 的瀏覽器。比如,使用 service workers 你可以緩衝應用外殼和你的應用所需的資料,所以這些資料在離線的環境下依然可以獲得。如果瀏覽器不支援 service workers ,支援離線的 代碼沒有工作,使用者也能得到一個基本的使用者體驗。使用特性檢測來漸漸增強有一些小的開銷,它不會在老舊的不支援 service workers 的瀏覽器中產生破壞性影響。

註冊 service worker

為了讓應用離線工作,要做的第一件事是註冊一個 service worker,一段允許在後台啟動並執行指令碼,不需要 使用者開啟 web 頁面,也不需要其他互動。

這隻需要簡單兩步:

  1. 建立一個 JavaScript 檔案作為 service worker
  2. 告訴瀏覽器註冊這個 JavaScript 檔案為 service worker

第一步,在你的應用根目錄下建立一個空檔案叫做 service-worker.js 。這個 service-worker.js 檔案必須放在跟目錄,因為 service workers 的作用範圍是根據其在目錄結構中的位置決定的。

接下來,我們需要檢查瀏覽器是否支援 service workers,如果支援,就註冊 service worker,將下面代碼添加至app.js中。

 
if(‘serviceWorker‘ in navigator) {  
    navigator.serviceWorker  
        .register(‘/service-worker.js‘)  
        .then(function() { console.log(‘Service Worker Registered‘); });  
}



緩衝網站的資源

當 service worker 被註冊以後,當使用者首次訪問頁面的時候一個 install 事件會被觸發。在這個事件的回呼函數中,我們能夠緩衝所有的應用需要再次用到的資源。

當 service worker 被啟用後,它應該開啟緩衝對象並將應用外殼需要的資源儲存進去。將下面這些代碼加入你的service-worker.js (你可以在your-first-pwapp-master/work中找到) :

 
var cacheName = ‘weatherPWA-step-6-1‘;
var filesToCache = [];

self.addEventListener(‘install‘, function(e) {
  console.log(‘[ServiceWorker] Install‘);
  e.waitUntil(
    caches.open(cacheName).then(function(cache) {
      console.log(‘[ServiceWorker] Caching app shell‘);
      return cache.addAll(filesToCache);
    })
  );
});

首先,我們需要提供一個緩衝的名字並利用 caches.open()開啟 cache 對象。提供的緩衝名允許我們給 緩衝的檔案添加版本,或者將資料分開,以至於我們能夠輕鬆地升級資料而不影響其他的緩衝。

一旦緩衝被開啟,我們可以調用 cache.addAll() 並傳入一個 url 列表,然後載入這些資源並將響應添加至緩衝。不幸的是 cache.addAll() 是原子操作,如果某個檔案快取失敗了,那麼整個緩衝就會失敗!

好的。讓我們開始熟悉如何使用DevTools並學習如何使用DevTools來調試service workers。在重新整理你的網頁前,開啟DevTools,從 Application 的面板中開啟 Service Worker 的窗格。它應該是這樣的:

當你看到這樣的空白頁,這意味著當前開啟的頁面沒有已經被註冊的Service Worker。

現在,重新載入頁面。Service Worker的窗格應該是這樣的:

當你看到這樣的資訊,這意味著頁面有個Service Worker正在運行。

現在讓我們來示範你在使用Service Worker時可能會遇到的問題。為了示範, 我們將把service-worker.js裡的install 的事件監聽器的下面添加在activate 的事件監聽器。

self.addEventListener(‘activate‘, function(e) {
  console.log(‘[ServiceWorker] Activate‘);
});
當 service worker 開始啟動時,這將會發射activate事件。

開啟DevTools並重新整理網頁,切換到應用程式面板的Service Worker窗格,在已被啟用的Service Worker中單擊inspect。理論上,控制台將會出現[ServiceWorker] Activate的資訊,但這並沒有發生。現在回去Service Worker窗格,你會發現到新的Service Worker是在“等待”狀態。

簡單來說,舊的Service Worker將會繼續控制該網頁直到標籤被關閉。因此,你可以關閉再重新開啟該網頁或者點擊 skipWaiting 的按鈕,但一個長期的解決方案是在DevTools中的Service Worker窗格啟用 Update on Reload 。當那個複選框被選擇後,當每次頁面重新載入,Service Worker將會強制更新

啟用 update on reload 複選框並重新載入頁面以確認新的Service Worker被啟用。

Note: 您可能會在應用程式面板裡的Service Worker窗格中看到類似於下面的錯誤資訊,但你可以放心的忽略那個錯誤資訊。

Ok, 現在讓我們來完成activate 的事件處理函數的代碼以更新緩衝。

self.addEventListener(‘activate‘, function(e) {  
  console.log(‘[ServiceWorker] Activate‘);  
  e.waitUntil(  
    caches.keys().then(function(keyList) {  
      return Promise.all(keyList.map(function(key) {  
        console.log(‘[ServiceWorker] Removing old cache‘, key);  
        if (key !== cacheName) {  
          return caches.delete(key);  
        }  
      }));  
    })  
  );  
});
確保在每次修改了 service worker 後修改 cacheName,這能確保你永遠能夠從緩衝中獲得到最新版本的檔案。過一段時間清理一下緩衝刪除掉沒用的資料也是很重要的。

最後,讓我們更新一下 app shell 需要的緩衝的檔案清單。在這個數組中,我們需要包括所有我們的應用需要的檔案,其中包括圖片、JavaScript以及樣式表等等。

var filesToCache = [  
  ‘/‘,  
  ‘/index.html‘,  
  ‘/scripts/app.js‘,  
  ‘/styles/inline.css‘,  
  ‘/images/clear.png‘,  
  ‘/images/cloudy-scattered-showers.png‘,  
  ‘/images/cloudy.png‘,  
  ‘/images/fog.png‘,  
  ‘/images/ic_add_white_24px.svg‘,  
  ‘/images/ic_refresh_white_24px.svg‘,  
  ‘/images/partly-cloudy.png‘,  
  ‘/images/rain.png‘,  
  ‘/images/scattered-showers.png‘,  
  ‘/images/sleet.png‘,  
  ‘/images/snow.png‘,  
  ‘/images/thunderstorm.png‘,  
  ‘/images/wind.png‘  
];
我麼的應用目前還不能離線工作。我們緩衝了 app shell 的組件,但是我們仍然需要從本機快取中載入它們。

從緩衝中載入 app sheel

Service workers 可以截獲 Progressive Web App 發起的請求並從緩衝中返迴響應。這意味著我們能夠 決定如何來處理這些請求,以及決定哪些網路響應能夠成為我們的緩衝。

比如:

self.addEventListener(‘fetch‘, function(event) {  
  // Do something interesting with the fetch here  
});
讓我們來從緩衝中載入 app shell。將下面代碼加入 service-worker.js 中:

self.addEventListener(‘fetch‘, function(e) {  
  console.log(‘[ServiceWorker] Fetch‘, e.request.url);  
  e.respondWith(  
    caches.match(e.request).then(function(response) {  
      return response || fetch(e.request);  
    })  
  );  
});
從內至外,caches.match() 從網路請求觸發的 fetch 事件中得到請求內容,並判斷請求的資源是 否存在於緩衝中。然後以緩衝中的內容作為響應,或者使用 fetch 函數來載入資源(如果緩衝中沒有該資源)。 response 最後通過 e.respondWith() 返回給 web 頁面。

測試

你的應用程式現在可以在離線下使用了! 讓我們來試試吧!

先重新整理那個網頁, 然後去DevTools裡的 Cache Storage 窗格中的 Application 面板上。展開該部分,你應該會在左邊看到您的app shell緩衝的名稱。當你點擊你的appshell緩衝,你將會看到所有已經被緩衝的資源。

現在,讓我們測試離線模式。回去DevTools中的 Service Worker 窗格,啟用 Offline 的複選框。啟用之後,你將會在 Network 窗格的旁邊看到一個黃色的警告圖示。這表示您處於離線狀態。

重新整理網頁,然後你會發現你的網頁仍然可以正常操作!

下一步驟是修改該應用程式和service worker的邏輯,讓氣象資料能夠被緩衝,並能在應用程式處於離線狀態,將最新的快取資料顯示出來。

Tip: 如果你要清除所有儲存的資料(localStoarge,IndexedDB的資料,快取檔案),並刪除任何的service worker,你可以在DevTools中的Application 面板裡的Clear storage清除。


當心邊緣問題

之前提到過,這段代碼 一定不要用在生產環境下 ,因為有很多沒有處理的邊界情況。

緩衝依賴於每次修改內容後更新緩衝名稱

比如緩衝方法需要你在每次改變內容後更新緩衝的名字。否則,緩衝不會被更新,舊的內容會一直被緩衝返回。 所以,請確保每次修改你的項目後更新緩衝名稱。

每次修改後所有資源都需要被重新下載

另一個缺點是當一個檔案被修改後,整個緩衝都需要被重新下載。這意味著即使你修改了一個簡單的拼字錯誤 也會讓整個緩衝重新下載。這不太高效。

瀏覽器的緩衝可能阻礙 service worker 的緩衝的更新

另外一個重要的警告。首次安裝時請求的資源是直接經由 HTTPS 的,這個時候瀏覽器不會返回緩衝的資源, 除此之外,瀏覽器可能返回舊的緩衝資源,這導致 service worker 的緩衝不會得到 更新。

在生產環境中當下 cache-first 策略

我們的應用使用了優先緩衝的策略,這導致所有後續請求都會從緩衝中返回而不詢問網路。優先緩衝的策略是 很容易實現的,但也會為未來帶來諸多挑戰。一旦首頁和註冊的 service worker 被緩衝下來,將會很難 去修改 service worker 的配置(因為配置依賴於它的位置),你會發現你部署的網站很難被升級。

我該如何避免這些邊緣問題

我們該如何避免這些邊緣問題呢? 使用一個庫,比如 sw-precache, 它對資源何時到期提供了 精細的控制,能夠確保請求直接經由網路,並且幫你處理了所有棘手的問題。

即時測試 service workers 提示

調試 service workers 是一件有調整性的事情,當涉及到緩衝後,當你期望緩衝更新,但實際上它並沒有的時候,事情更是變得像一場惡夢。在 service worker 典型的生命週期和你的代碼之間,你很快就會受挫。但幸運的是,這裡有一些工具可以讓你的生活更加簡單。

其他的提示:

一旦 service worker 被登出(unregistered)。它會繼續作用直到瀏覽器關閉。
如果你的應用開啟了多個視窗,新的 service worker 不會工作,直到所有的視窗都進行了重新整理,使用了 新的 service worker。
登出一個 service worker 不會清空緩衝,所以如果緩衝名沒有修改,你可能繼續獲得到舊的資料。
如果一個 service worker 已經存在,而且另外一個新的 service worker 已經註冊了,這個新的 service worker 不會接管控制權,知道該頁面重新重新整理後,除非你使用立刻控制的方式。

使用 Service Workers 來預緩衝應用外殼

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.