Register for this year’s #ChromeDevSummit happening on Nov. 11-12 in San Francisco to learn about the latest features and tools coming to the Web. Request an invite on the Chrome Dev Summit 2019 website

在網絡應用中添加服務工作線程和離線功能

概覽

9246b0abd8d860da.png

在此代碼實驗室中,您將學習如何將服務工作線程集成到現有應用內,以使應用能夠離線工作。該應用名爲 Air Horner。點擊喇叭就會發聲。

您將學習的內容

  • 如何向現有項目添加基礎服務工作線程。
  • 如何使用 Chrome DevTools 模擬離線模式以及檢查和調試服務工作線程。
  • 一種簡單的離線緩存策略。

您需具備的條件

  • Chrome 52 或更高版本。
  • Promises、Git 和 Chrome DevTools 的基本瞭解。
  • 示例代碼。
  • 文本編輯器。
  • 本地網絡服務器。如果您想要使用此代碼實驗室中所述的網絡服務器,則需要在命令行中安裝 Python。

獲取示例代碼

通過 SSH 從命令行克隆 GitHub 存儲區。

$ git clone git@github.com:GoogleChrome/airhorn.git

或 HTTPS:

$ git clone https://github.com/GoogleChrome/airhorn.git

運行應用示例

首先,我們先看看應用示例的最終樣子(提示:太奇妙了)。

通過查看 master 分支確保您位於正確的(最終)分支。

$ git checkout master

從本地網絡服務器運行網站。您可以使用任意網絡服務器,但對於此代碼實驗室的其他部分,我們假定您在端口 3000 上使用的是 Python 的 SimpleHTTPServer,以便從 localhost:3000 中運行應用。

$ cd app
$ python -m SimpleHTTPServer 3000

在 Chrome 中打開網站。您會看到:9246b0abd8d860da.png

測試應用

點擊喇叭,應能發聲。

現在,您可以使用 Chrome DevTools 模擬離線模式了。

打開 DevTools,轉至 Application 面板,然後啓用 Offline 複選框。在下面的屏幕截圖中,鼠標懸停在複選框上。

479219dc5f6ea4eb.png

點擊複選框後,請注意 Network 面板標籤旁邊的警告圖標(帶有感嘆號的黃色三角形)。這表示您處於離線狀態。

如需證明您處於離線模式,請轉至 https://google.com。您會看到 Chrome 的“there is no Internet connection”錯誤消息。

現在,返回到應用中。儘管您處於離線狀態,頁面應仍然能夠完全重新加載。您應仍然能夠使用喇叭。

它能夠離線工作的原因就是此 代碼實驗室的基礎:通過服務工作線程提供離線支持。

構建初學者應用

您現在將要刪除應用中的所有離線支持,學習如何使用服務工作線程重新將離線支持添加到應用中

請查看應用的“斷開”版本,此版本未實現服務工作線程。

$ git checkout code-lab

返回到 DevTools 的 Application 面板,禁用 Offline 複選框,以便重新返回在線狀態。

運行頁面。應用應能如期運行。

現在,使用 DevTools 重新模擬離線模式(通過在 Application 面板中啓用 Offline 複選框)。__注意!如果您不是非常瞭解服務工作線程,則會看到一些異常行爲。

您可能會看到什麼?因爲您處於離線狀態,並且這個版本的應用沒有服務工作線程,您將看到 Chrome 中顯示典型的“there is no Internet connection”錯誤消息。

但您實際看到的是...功能完備的離線應用!

9246b0abd8d860da.png

這是怎麼回事?回想一下您在開始此代碼實驗室時的情景,您嘗試了應用的完整版本。當您運行那個版本時,應用實際上安裝了服務工作線程。現在,在您每次運行應用時,服務工作線程都會自動運行。一旦 localhost:3000 等作用域(您將會在下一部分中瞭解有關作用域的更多內容)中安裝了服務工作線程,服務工作線程會在您每次訪問作用域時自動啓動,除非您以編程方式或手動將其刪除。

如需修復這一問題,請轉至 DevTools 的 Application 面板,點擊 Service Workers 選項卡,然後點擊 Unregister 按鈕。在下面的屏幕截圖中,鼠標懸停在按鈕上。

837b46360756810a.png

現在,在您重新加載網站之前,請確保您仍然在使用 DevTools 模擬離線模式。重新加載頁面,應會如期顯示“there is no Internet connection”錯誤消息。

da11a350ed38ad2e.png

在網站上註冊服務工作線程

現在,可以將離線支持重新添加到應用中。這個過程由兩個步驟組成:

  1. 創建一個將作爲服務工作線程的 JavaScript 文件。
  2. 指示瀏覽器將此 JavaScript 文件註冊爲“服務工作線程”。

首先,創建一個名爲 sw.js 的空白文件,然後將其放入 /app 文件夾。

現在打開 index.html,並將以下代碼添加到 <body> 底部。

<script>
if('serviceWorker' in navigator) {
  navigator.serviceWorker
           .register('/sw.js')
           .then(function() { console.log("Service Worker Registered"); });
}
</script>

腳本會檢查瀏覽器是否支持服務工作線程。如果不支持,它會將我們當前使用的空白文件 sw.js 註冊爲服務工作線程,然後記錄到控制檯。

在重新運行網站之前,返回到 DevTools,查看 Application 面板的 __Service Workers __ 標籤。此標籤當前應爲空,表示網站沒有安裝服務工作線程。

37d374c4b51d273.png

確保已停用 DevTools 中的 Offline 複選框。重新加載頁面。在加載頁面時,您可以看到服務工作線程已經完成註冊。

b9af9805d4535bd3.png

Source 標籤旁邊,您可以看到已註冊的服務工作線程源代碼的鏈接。

3519a5068bc773ea.png

如果您想要檢查當前爲頁面安裝的服務工作線程,請點擊鏈接。這將會在 DevTools 的 Sources 面板中爲您顯示服務工作線程的源代碼。例如,現在點擊鏈接,您會看到一個空文件。

dbc14cbb8ca35312.png

安裝網站資產

註冊服務工作線程後,當用戶首次點擊頁面時,會觸發 install 事件。此事件就是您要緩存頁面資產的地方。

將以下代碼添加到 sw.js。

importScripts('/cache-polyfill.js');


self.addEventListener('install', function(e) {
 e.waitUntil(
   caches.open('airhorner').then(function(cache) {
     return cache.addAll([
       '/',
       '/index.html',
       '/index.html?homescreen=1',
       '/?homescreen=1',
       '/styles/main.css',
       '/scripts/main.min.js',
       '/sounds/airhorn.mp3'
     ]);
   })
 );
});

第一行會添加緩存 polyfill。此 polyfill 已經添加到存儲區。我們需要使用 polyfill 是因爲 Cache API 尚未在所有瀏覽器中得到完全支持。接下來是 install 事件偵聽器。install 事件偵聽器可以打開 caches 對象,然後使用我們要緩存的資源列表進行填充。關於 addAll 操作的一個重要事情就是要麼全部添加,要麼全部不添加。如果其中有一個文件不存在或無法抓取,整個 addAll 操作將會失敗。合格的應用將會處理這種情況。

下一步是對服務工作線程編程,以將任意資源的請求返回給攔截,並使用 caches 對象返回每個資源的本地存儲版本。

攔截網頁請求

服務工作線程的一個強大的功能就是,一旦它控制頁面,就可以攔截頁面發出的每個請求,並確定對請求執行的操作。在本部分中,您將對服務工作線程進行編程,以攔截請求並返回緩存版本的資產,而不是到網絡上檢索這些資產。

第一步是將一個事件處理程序附加到 fetch 事件。發出的每個請求都會觸發此事件。

將以下代碼添加到 sw.js 的底部,以便記錄父頁面發出的請求。

我們來測試一下這個功能。注意!您將會看到更加異常的服務工作線程行爲。

打開 DevTools,轉至 Application 面板。應停用 Offline 複選框。按 Esc 鍵以打開 DevTools 窗口底部的 Console 抽屜。您的 DevTools 窗口應類似於以下屏幕截圖:

c96de824be6852d7.png

現在重新加載頁面並查看 DevTools 窗口。首先,我們預期能看到記錄到控制檯中的大量請求,但沒有看到。其次,在 __Service Worker __窗格中,我們可以看到 Status 已發生更改:

c7cfb6099e79d5aa.png

Status 中,有一個新的服務工作線程正等待激活。這就是包含我們剛纔所做更改的新的服務工作線程。因此,出於某種原因,我們以前安裝的舊的服務工作線程(空白文件)仍然在控制頁面。如果您點擊 Source 旁邊的 sw.js 鏈接,便可驗證舊的服務工作線程仍然在運行中。

如需修復這種不便,請啓用 Update on reload 複選框。

26f2ae9a805bc69b.png

啓用此複選框後,DevTools 會始終在每個頁面重新加載時更新服務工作線程。這在主動開發服務工作線程時非常有用。

現在重新加載頁面,就會看到系統安裝了新的服務工作線程,並且正在將請求網址記錄到控制器,如預期一樣。

53c23650b131143a.png

現在,您需要確定使用這些請求要完成的任務。默認情況下,如果您未進行任何設置,請求會傳遞到網絡,系統會將響應返回到網頁。

要使應用離線工作,如果緩存中存在請求,我們需要從中獲取請求。

請更新您的抓取事件偵聽器,以匹配以下代碼。

event.respondWith() 方法會讓瀏覽器評估未來事件的結果。caches.match(event.request) 會獲取觸發抓取事件的當前網絡請求,在緩存中尋找匹配的資源。匹配通過查找網址字符串執行。match 方法會返回可解析的 promise,即使未在緩存中找到相關文件。這意味着您可以選擇要執行的操作。在您的簡單案例中,如果未找到文件,您會想要從網絡中 fetch 它,然後將其返回到瀏覽器。

這是最簡單的情況,還有許多其他緩存情境。例如,您可以增量方式緩存之前未緩存請求的所有響應,以便以後從緩存返回這些響應。

恭喜!

現在您獲得離線支持了。在您處於在線狀態時重新加載頁面,將服務工作線程更新爲最新版本,然後使用 DevTools 轉至離線模式。重新加載頁面,就可以擁有功能完備的離線汽笛了!

我們已經闡述的內容

  • 如何向現有項目添加基礎服務工作線程。
  • 如何使用 Chrome DevTools 模擬離線模式以及檢查和調試服務工作線程。
  • 一種簡單的離線緩存策略。

後續步驟

瞭解詳情

發現問題,或者有反饋?

立即提交問題,幫助我們讓代碼實驗室更加強大。謝謝!