摘要:生命周期的生命周期和網(wǎng)頁完全不相關。意即會作用于整個源地址上。激活安裝完之后下一步即激活。同時檢查響應類型是否為,即檢查請求是否同域。創(chuàng)建新的的過程將會啟動,然后觸發(fā)事件??梢岳媒俪志W(wǎng)絡連接和偽造響應數(shù)據(jù)。
原文請查閱這里,略有刪減,本文采用知識共享署名 4.0 國際許可協(xié)議共享,BY Troland。
本系列持續(xù)更新中,Github 地址請查閱這里。
這是 JavaScript 工作原理的第八章。
或許你已經(jīng)了解到漸進式網(wǎng)絡應用將只會越來越流行,因為它旨在創(chuàng)造擁有更加流暢的用戶體驗的網(wǎng)絡應用和創(chuàng)建類 App 的原生應用體驗而非瀏覽器端那樣的外觀和體驗。
構建漸進式網(wǎng)絡應用的主要需求之一即在各種網(wǎng)絡和數(shù)據(jù)加載的條件下仍然可用-它可以在網(wǎng)絡不穩(wěn)定或者沒有網(wǎng)絡的情況下使用。
本文我們將會深入了解 Service Workers:它們是如何工作的以及你所應該關切的方面。最后,我們將會列出一些Service Workers 可供利用的,獨有的優(yōu)勢并且分享我們在 SessionStack 中的團隊實踐經(jīng)驗。
概述若想理解 Service Workers 相關的一切,你首先應該閱讀一下之前發(fā)布的有關 Web Workers 的文章。
大體上,Service Worker 是一種 Web Worker,更準確地說,它更像是一個 Shared Worker。
Service Worker 運行在其全局腳本上下文中
不指定和某個網(wǎng)頁綁定
不能夠訪問 DOM
Service Worker 接口之所以讓人感到興奮的原因之一即它支持網(wǎng)絡應用離線運行,這使得開發(fā)者能夠完全控制網(wǎng)絡應用的行為。
生命周期Service Worker 的生命周期和網(wǎng)頁完全不相關。它由以下幾個步驟組成:
下載
安裝
激活
下載這發(fā)生于瀏覽器下載包含 Service Worker 相關代碼的 .js 文件。
安裝為了在網(wǎng)絡應用中使用 Service Worker,首先得在 JavaScript 代碼中對其進行注冊。當 Service Worker 注冊的時候,它會讓瀏覽器在后臺開始安裝 Service Worker 的步驟。
通過注冊 Service Worker,瀏覽器知曉包含 Service Worker 相關代碼的 JavaScript 文件??聪氯缦麓a:
if ("serviceWorker" in navigator) { window.addEventListener("load", function() { navigator.serviceWorker.register("/sw.js").then(function(registration) { // 注冊成功 console.log("ServiceWorker registration successful"); }, function(err) { // 注冊失敗 console.log("ServiceWorker registration failed: ", err); }); }); }
以上代碼首先檢查當前執(zhí)行環(huán)境是否支持 Service Worker API。如果是,則注冊 /sw.js Service Worker。
可以在每次頁面加載的時候,任意調(diào)用 register()-瀏覽器會檢測 service worker 是否已經(jīng)注冊從而進行適當?shù)靥幚怼?/p>
register() 方法里面需要特別注意的地方即 Service Worker 文件地址。當前示例是在服務器根目錄下。意即 service worker 會作用于整個源地址上。換句話說,即 service worker 會接收到該域名下所有頁面 的 fetch 事件。如果注冊 service worker 的文件路徑是 /example/sw.js ,那么 service worker 會接收到所有頁面路徑以 /example/ 為開頭的 URL 地址的 fetch 事件(比如 /example/page1/ /example/page2/)。
在安裝階段,最好加載和緩存一些靜態(tài)資源。一旦靜態(tài)資源緩存成功,Service Worker 的安裝也就完成了。倘若加載失?。璖ervice Worker 將會重試。一旦安裝成功,靜態(tài)資源也就緩存成功了。
這也就回答了為什么要在 load 事件之后注冊 Service Worker。這不是必須的,但是強烈推薦這么做。
為什么要這樣做呢?假設用戶第一次訪問網(wǎng)絡應用?,F(xiàn)在還沒有注冊 service worker,而且瀏覽器無法事先知曉是否會最終安裝它。如果進行安裝,則瀏覽器將會為增加的線程開辟額外的 CPU 和內(nèi)存,而這些資源原本是用來渲染網(wǎng)頁的。
參考下這里,load 事件會加載完所有的資源比如圖片,樣式之后觸發(fā)。
最終的結(jié)果即是如果在頁面中安裝 Service Worker,將有可能導致頁面延遲加載和渲染-不能夠讓用戶盡快地訪問網(wǎng)頁。
需要注意的是這只會發(fā)生在第一次訪問頁面的時候。后續(xù)的頁面訪問不會被 Service Worker 的安裝所影響。一旦在首次訪問頁面的時候激活了 Service Worker?,它就可以處理后續(xù)的頁面訪問所觸發(fā)的頁面加載/緩存事件。這是正確的,Service Worker 需要加載好以處理有限的網(wǎng)絡帶寬。
激活安裝完之后下一步即激活。該步驟是操作之前緩存資源的絕佳時機。
一旦激活,Service Worker 就可以開始控制在其作用域內(nèi)的所有頁面。一個有趣的事實即:注冊了 Service Worker 的頁面直到再次加載的時候才會被 Service Worker 進行處理。當 Service Worker 開始進行控制,它有以下幾種狀態(tài):
處理來自頁面的網(wǎng)絡或者消息請求所觸發(fā)的 fetch 及 message 事件
中止以節(jié)約內(nèi)存
以下即其生命周期:
處理 Service Worker 內(nèi)部的安裝過程在頁面運行注冊 Service Worker 的過程中,讓我們來看看 Service Worker 腳本中發(fā)生的事情,它監(jiān)聽 Service Worker 實例的 install 事件。
以下為處理 install 事件所需要執(zhí)行的步驟:
打開緩存
緩存文件
確認是否所有的靜態(tài)資源已緩存
以下為一個 Service Worker 內(nèi)部可能的簡單安裝代碼:
var CACHE_NAME = "my-web-app-cache"; var urlsToCache = [ "/", "/styles/main.css", "/scripts/app.js", "/scripts/lib.js" ]; self.addEventListener("install", function(event) { // event.waitUntil 使用 promise 來獲得安裝時長及安裝是否失敗 event.waitUntil( caches.open(CACHE_NAME) .then(function(cache) { console.log("Opened cache"); return cache.addAll(urlsToCache); }) ); });
如果文件都成功緩存,則 service worker 安裝成功。如果任意文件下載失敗,那么 service worker 將會安裝失敗。因此,請注意需要緩存的文件。
處理 install 事件完全是可選,當不進行處理的時候,跳過以上幾個步驟即可。
緩存運行時請求該部分才是干貨。在這里可以看到如何攔截請求然后返回已創(chuàng)建的緩存(以及創(chuàng)建新的緩存)。
當 Service Worker 安裝完成之后,用戶會導航到另一個頁面或者刷新當前頁面,Service Worker 將會收到 fetch 事件。這里有一個演示了如何返回緩存的靜態(tài)資源或執(zhí)行一個新的請求并緩存返回結(jié)果的過程的示例:
self.addEventListener("fetch", function(event) { event.respondWith( // 該方法查詢請求然后返回 Service Worker 創(chuàng)建的任何緩存數(shù)據(jù)。 caches.match(event.request) .then(function(response) { // 若有緩存,則返回 if (response) { return response; } // 復制請求。請求是一個流且只能被使用一次。因為之前已經(jīng)通過緩存使用過一次了,所以為了在瀏覽器中使用 fetch,需要復制下該請求。 var fetchRequest = event.request.clone(); // 沒有找到緩存。所以我們需要執(zhí)行 fetch 以發(fā)起請求并返回請求數(shù)據(jù)。 return fetch(fetchRequest).then( function(response) { // 檢測返回數(shù)據(jù)是否有效 if(!response || response.status !== 200 || response.type !== "basic") { return response; } // 復制返回數(shù)據(jù),因為它也是流。因為我們想要瀏覽器和緩存一樣使用返回數(shù)據(jù),所以必須復制它。這樣就有兩個流 var responseToCache = response.clone(); caches.open(CACHE_NAME) .then(function(cache) { // 把請求添加到緩存中以備之后的查詢用 cache.put(event.request, responseToCache); }); return response; } ); }) ); });
大概的流程如下:
event.respondWith() 會決定如何響應 fetch 事件。 caches.match() 查詢請求然后返回之前創(chuàng)建的緩存中的任意緩存數(shù)據(jù)并返回 promise。
如果有,則返回該緩存數(shù)據(jù)。
否則,執(zhí)行 fetch 。
檢查返回的狀態(tài)碼是否是 200。同時檢查響應類型是否為 basic,即檢查請求是否同域。當前場景不緩存第三方資源的請求。
把返回數(shù)據(jù)添加到緩存中。
因為請求和響應都是流而流數(shù)據(jù)只能被使用一次,所以必須進行復制。而且由于緩存和瀏覽器都需要使用它們,所以必須進行復制。
更新 Service Worker當用戶訪問網(wǎng)絡應用的時候,瀏覽器會在后臺試圖重新下載包含 Service Worker 代碼的 .js 文件。
如果下載下來的文件和當前的 Service Worker 代碼文件有一丁點兒不同,瀏覽器會認為文件發(fā)生了改變并且會創(chuàng)建一個新的 Service Worker。
創(chuàng)建新的 Service Worker 的過程將會啟動,然后觸發(fā) install 事件。然而,這時候,舊的 Service Worker 仍然控制著網(wǎng)絡應用的頁面意即新的 Service Worker 將會處于 waiting 狀態(tài)。
一旦關閉網(wǎng)絡應用當前打開的頁面,舊的 Service Worker 將會被瀏覽器殺死而新的 Service Worker 就可以上位了。這時候?qū)|發(fā) activate 事件。
為什么所有這一切是必須的呢?這是為了避免在不同選項卡中同時運行不同版本的的網(wǎng)絡應用所造成的問題-一些在網(wǎng)頁中實際存在的問題且有可能會產(chǎn)生新的 bug(比如當在瀏覽器中本地存儲數(shù)據(jù)的時候卻擁有不同的數(shù)據(jù)庫結(jié)構)。
從緩存中刪除數(shù)據(jù)activate 回調(diào)中最為常見的步驟即緩存管理。因為若想刪除安裝步驟中老舊的緩存,而這又會導致 Service Workers 無法獲取該緩存中的文件數(shù)據(jù),所以,這時候需要進行緩存管理。
這里有一個示例演示如何把未在白名單中的緩存刪除(該情況下,以 page-1 或者 page-2 來進行命名):
self.addEventListener("activate", function(event) { var cacheWhitelist = ["page-1", "page-2"]; event.waitUntil( // 獲得緩存中所有鍵 caches.keys().then(function(cacheNames) { return Promise.all( // 遍歷所有的緩存文件 cacheNames.map(function(cacheName) { // 若緩存文件不在白名單中,刪除之 if (cacheWhitelist.indexOf(cacheName) === -1) { return caches.delete(cacheName); } }) ); }) ); });HTTPS 要求
當處于開發(fā)階段的時候,可以通過 localhost 來使用 Service Workers?,但當處于發(fā)布環(huán)境的時候,必須部署好 HTTPS(這也是使用 HTTPS 的最后一個原因了)。
可以利用 Service Worker劫持網(wǎng)絡連接和偽造響應數(shù)據(jù)。如果不使用 HTTPS,網(wǎng)絡應用會容易遭受中間人 攻擊。
為了保證安全,必須通過 HTTPS 在頁面上注冊 Service Workers,這樣就可以保證瀏覽器接收到的 Service Worker 沒有在傳輸過程中被篡改。
瀏覽器支持Service Workers 擁有良好的瀏覽器兼容性。
你可以追蹤所有瀏覽器的支持進程:
https://jakearchibald.github....
Service Workers 提供了更多的功能的可能Service Worker 獨有的功能:
推送通知-允許用戶選擇定時接收網(wǎng)絡應用的推送更新
后臺同步-允許延遲操作直到網(wǎng)絡連接穩(wěn)定之后。這樣就可以保證用戶即時發(fā)送數(shù)據(jù)。
定期同步(以后支持)-提供了管理進行定期后臺數(shù)據(jù)同步的功能
Geofencing (以后支持)-可以自定義參數(shù),也即 geofences ,該參數(shù)包含著用戶所感興趣的地區(qū)。當設備穿過某片地理圍欄的時候會收到通知,這就能夠讓你基于用戶的地理位置來提供有用的用戶體驗。
這里提到的每個功能將會該系列之后的文章中進行詳細闡述。
我們持續(xù)不斷地工作以讓 SessionStack 的交互體驗盡可能流暢,優(yōu)化頁面加載時間和響應時間。
當在 SessionStack 上重放用戶會話或者實時流播放,SessionStack 界面會從服務器持續(xù)抓取數(shù)據(jù)從而為用戶創(chuàng)造一個類緩沖的使用體驗(類似視頻緩沖那種)。再詳細了解一些原理即一旦在網(wǎng)絡應用中集成 SessionStack 庫,它將會持續(xù)收集諸如 DOM 變化,用戶交互,網(wǎng)絡請求,未處理異常以及調(diào)試信息的數(shù)據(jù)。
當重放或者實時觀看一個會話的時候,SessionStack 會返回所有數(shù)據(jù)以方便觀察發(fā)生于用戶瀏覽器的所有事件。(視覺上和技術上的)。所有的這一切都是即時發(fā)生的,因為我們不想讓用戶等待。
由于數(shù)據(jù)是由前端抓取的,這個時候就可以使用 Service?Workers 來處理類似播放器重載和再次流傳輸所有數(shù)據(jù)的情形。處理緩慢的網(wǎng)絡連接也是非常重要的。
參見維基百科關于流的定義,可以更好地理解這里的流的概念。
本系列持續(xù)更新中,Github 地址請查閱這里。
文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/95310.html
摘要:的生命周期的生命周期與頁面完全分離。換句話說,這個將為這個域中的所有內(nèi)容接收事件。這不是必要的,但絕對是推薦的。新的將啟動并且安裝事件將被移除。使用,可以很容易被劫持連接并偽造響應。后臺同步允許延遲操作,直到用戶具有穩(wěn)定的連接。 這是專門探索 JavaScript 及其所構建的組件的系列文章的第8篇。 想閱讀更多優(yōu)質(zhì)文章請猛戳GitHub博客,一年百來篇優(yōu)質(zhì)文章等著你! 如果你錯過了前...
摘要:的生命周期生命周期與您的網(wǎng)頁是完全分開。激活安裝之后,下一步是將其激活。一旦激活,將開始控制所有屬于其范圍的頁面。否則,將執(zhí)行事件。響應結(jié)果被添加到緩存中。請求和響應必須被克隆,因為它們是流。新的將啟動并且事件將被觸發(fā)。 showImg(https://segmentfault.com/img/bV9Sa2?w=800&h=410);您可能已經(jīng)知道,漸進式Web應用(PWA)會越來越受...
摘要:為了方便大家共同學習,整理了之前博客系列的文章,目前已整理是如何工作這個系列,可以請猛戳博客查看。以下列出該系列目錄,歡迎點個星星,我將更友動力整理理優(yōu)質(zhì)的文章,一起學習。 為了方便大家共同學習,整理了之前博客系列的文章,目前已整理 JavaScript 是如何工作這個系列,可以請猛戳GitHub博客查看。 以下列出該系列目錄,歡迎點個星星,我將更友動力整理理優(yōu)質(zhì)的文章,一起學習。 J...
摘要:字節(jié)流這個簡單的模型將數(shù)據(jù)存儲為長度不透明的字節(jié)字符串變量,將任何形式的內(nèi)部組織留給應用層。字節(jié)流數(shù)據(jù)存儲的代表例子包括文件系統(tǒng)和云存儲服務。使用同步存儲會阻塞主線程,并為應用程序的創(chuàng)建凍結(jié)體驗。 這是專門探索 JavaScript 及其所構建的組件的系列文章的第 16 篇。 想閱讀更多優(yōu)質(zhì)文章請猛戳GitHub博客,一年百來篇優(yōu)質(zhì)文章等著你! 如果你錯過了前面的章節(jié),可以在這里找到它...
閱讀 923·2023-04-25 19:28
閱讀 1607·2021-09-10 10:51
閱讀 2547·2019-08-30 15:55
閱讀 3544·2019-08-26 13:55
閱讀 3150·2019-08-26 13:24
閱讀 3462·2019-08-26 11:46
閱讀 2886·2019-08-23 17:10
閱讀 1565·2019-08-23 16:57