前提
本文涉及幾個知識點:fetch、caches、indexDB 等都不會詳細(xì)介紹,僅對于其中某些點帶過
serviceWorker,服務(wù)工作線程,顧名思義,只是作為工作線程存在,不摻和到JS主線程中來,介于 瀏覽器 & 服務(wù)器中間層,可攔截指定 client 所發(fā)起的所有請求
目前 PWA(Progress Web App) 的概念很火,大致就是讓 web 也跟 app 一樣,可以實現(xiàn)添加到桌面、消息推送、離線使用等功能,如 餓了么 在三月份左右就在H5上整了個 PWA 的頁面。而其中的關(guān)鍵點,其實就是離線使用的功能,也就是 sw 在其中的作用。由于 sw 可以攔截 client 的請求,也就是能夠根據(jù)請求,把請求后的 response 用瀏覽器緩存 caches 緩存下來,以實現(xiàn)離線的使用
說到 sw 的生命周期,就得祭奠出這張圖了
步驟分為以下部分:
register?這個是由 client 端發(fā)起,注冊一個 serviceWorker,這需要一個專門的 sw 處理文件
install?注冊成功后,此時 sw 中會觸發(fā) install 事件, 需知 sw 中都是事件觸發(fā)的方式進(jìn)行的邏輯調(diào)用
activate?安裝后要等待激活,也就是 activated 事件,只要 register 成功后就會觸發(fā) install ,但不會立即觸發(fā) activated,這個稍后再說
idle?在 activated 之后就可以開始對 client 的請求進(jìn)行攔截處理,sw 發(fā)起請求用的是 fetch api
fetch 激活以后開始對網(wǎng)頁中發(fā)起的請求進(jìn)行攔截處理
terminate?這一步是瀏覽器自身的判斷處理,當(dāng) sw 長時間不用之后,處于閑置狀態(tài),瀏覽器會把該 sw 暫停,直到再次使
update 瀏覽器會自動檢測 sw 文件的更新,當(dāng)有更新時會下載并 install,但頁面中還是老的 sw 在控制,只有當(dāng)用戶新開窗口后新的 sw 才能激活控制頁面
fetch?
發(fā)送請求時,默認(rèn)不會帶上cookie,發(fā)送請求時若想帶上cookie,得顯示設(shè)定?{ credential: "include" }
對于跨域的資源,把模式設(shè)置為跨域?{ mode: "cors" },否則 response 中拿不到對應(yīng)的數(shù)據(jù)
caches
只能緩存 GET?& HEAD?的請求,當(dāng)然安全起見
以上,對于 POST 等類型請求,返回數(shù)據(jù)可以保存在 indexDB 中
serviceWorker
注冊的 sw 資源文件,只能監(jiān)聽該 sw 的路徑 & 之后子路徑的請求,這個怎么理解呢:也就是若資源是 /app/sw.js ,打印出來 registration.scope === /app/ 則只能監(jiān)聽 /app/ 下的資源,不能監(jiān)聽其他 path,就連 /app 的也不行 !!!這意味著什么,意味著你在 /app 目錄下注冊的 /app/sw.js,訪問 /app 時不會生效 !
sw 提供了參數(shù)可以設(shè)定 scope 去設(shè)定監(jiān)聽的某一路徑,那么我們想讓 /app 生效,得怎么做呢,其實就是得把 sw.js 放在根目錄 / ,然后設(shè)置 { scope: "/app" } 就好了
在 sw 中 js 報錯,不會被 client 的監(jiān)控捕獲到,因此,必須要專門對 sw 的錯誤進(jìn)行處理
基于 a 可知:sw 注冊文件,不能放在 CDN 上,必須在當(dāng)前意圖監(jiān)聽的 client 的 domain 下
Request & Response 中的 body 只能被讀取一次,究其原因,是其中包含 bodyUsed 屬性,當(dāng)使用過后,這個屬性值就會變?yōu)?true, 不能再次讀取,解決方法是,把 Request & Response clone 下來: request.clone() || response.clone()
client 端新建頁面文件?index.js? & sw 注冊文件 serviceWorker.js
把幾個點都考慮好:漸進(jìn)增強、出錯降級
!(function (win) { const sw = win.navigator.serviceWorker const killSW = win.killSW || false if (!sw) { return } if (!!killSW) { sw.getRegistration("/serviceWorker").then(registration => { // 手動注銷 registration.unregister() }) } else { // 表示該 sw 監(jiān)聽的是根域名下的請求 sw.register("/serviceWorker.js").then(registration => { // 注冊成功后會進(jìn)入回調(diào) console.log(registration.scope) }).catch(err => { console.error(err) }) } })(window)
編寫 serviceWorker.js 文件,注意 sw 的所有接口都是 promise 形式回調(diào)的
第一步:監(jiān)聽 install 事件,sw 基于事件驅(qū)動!
self.addEventListener("install", event => { console.log("installed") ... })
第二步:監(jiān)聽 activate 事件,sw install 之后不會立即生效,除非新打開頁面,否則當(dāng)前頁面會一直是舊的 sw 掌控,因此有必要在 activate 后再對當(dāng)前頁面的緩存等進(jìn)行一定的處理
// 定義不同 path 下的 cahche name const CACHE_NAME = "TEST1" self.addEventListener("activate", event => { console.log("activated") event.waitUntil( // 刪除舊文件 caches.keys().then(cacheNames => { return Promise.all( cacheNames.map((cacheName) => { return caches.delete(cacheName); }) ); }) ); })
瀏覽器緩存 caches 會一直保存存存存到存不動了,再去刪除某些資源,這個是瀏覽器的行為,因此還是建議在每次更改后去刪除一些舊的瀏覽器資源,可以自己設(shè)定
第三步:開始監(jiān)聽頁面發(fā)起的請求
sw 中用的是 fetch api 去請求相應(yīng)的資源,但不代表 client 中得用 fetch ,所有頁面的請求都會轉(zhuǎn)變?yōu)?fetch 事件被 sw 捕獲
event.respondWith 接收的是一個 promise 參數(shù),把其結(jié)果返回到 client 中
fetch 分為三大模塊 Header、Request、Response ,這里并不打算詳說,可以自行去了解
self.addEventListener("fetch", event => { let { request } = event event.respondWith( // 先從 caches 中尋找是否有匹配 caches.match(request).then(res => { if (res) { return res } // 對于 CDN 資源要更改 request 的 mode if (request.mode !== "navigate" && request.url.indexOf(request.referrer) === -1) { request = new Request(request, { mode: "cors" }) } // 對于不在 caches 中的資源進(jìn)行請求 return fetch(request).then(fetchRes => { // 這里只緩存成功 && 請求是 GET 方式的結(jié)果,對于 POST 等請求,可把 indexDB 給用上 if(!fetchRes || fetchRes.status !== 200 || request.method !== "GET") { return fetchRes } let resClone = fetchRes.clone() caches.open(CACHE_NAME).then(cache => { cache.put(request, fetchRes) }) return resClone }) }) ) })
文件到這里就基本準(zhǔn)備好了 ~ 寫個 html 文件去調(diào)用 index.js 看看效果吧
調(diào)試有幾種方法:
控制臺 Application 中查看 sw 的生命
chrome://inspect/#service-workers?可查看當(dāng)前打開的所有網(wǎng)站的 sw 資源,可以進(jìn)行調(diào)試(但是其實直接在 source 中就可以進(jìn)行調(diào)試的我發(fā)現(xiàn),不需要這么麻煩 ?==)
未完待續(xù) ...
其實還沒有真正把這個用到項目中去,sw 文件的放置路徑就是個大問題,現(xiàn)在所有靜態(tài)文件都在 CDN 上,得多帶帶為它開個 VIP,能通過 client 的 host 直接訪問到的;
另外 餓了么 之前還很開心的宣布用上了 PWA ,但是最近不知道為啥給下線了,害怕!
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/88356.html
摘要:用于簡單可擴展的狀態(tài)管理,相比有更高的靈活性,文檔參考中文文檔,本文作為入門,介紹一個簡單的項目。任務(wù)已完成下一個任務(wù)修復(fù)谷歌瀏覽器頁面顯示問題提交意見反饋代碼創(chuàng)建在中引入主入口文件設(shè)置參考入門學(xué)習(xí)總結(jié) MobX用于簡單、可擴展的React狀態(tài)管理,相比Redux有更高的靈活性,文檔參考:MobX中文文檔,本文作為入門,介紹一個簡單的TodoList項目。 1. 預(yù)期效果 showIm...
摘要:漸進(jìn)式應(yīng)用入門教程上在這一節(jié)中,我們將介紹的原理是什么,它是如何開始工作的。第一步使用漸進(jìn)式應(yīng)用程序需要使用連接。優(yōu)先旋轉(zhuǎn)方向,可選的值有顯示方式無,和原生應(yīng)用一樣,最小的一套控件集或者最古老的使用瀏覽器標(biāo)簽顯示一個包含所有圖片的數(shù)組。 上篇文章我們對漸進(jìn)式Web應(yīng)用(PWA)做了一些基本的介紹。 漸進(jìn)式Web應(yīng)用(PWA)入門教程(上) 在這一節(jié)中,我們將介紹PWA的原理是什么,它是...
摘要:現(xiàn)在表示公開支持。一旦安裝完成,如果注冊的沒有變化,則顯示為已激活的生命周期結(jié)束。一旦安裝這步完成,便會激活,并控制在其范圍內(nèi)的一切。目前還在草案狀態(tài),僅火狐和谷歌瀏覽器支持此特性。 PWA初探 什么是PWA PWA(Progressive Web Apps):漸進(jìn)式 Web app PWA 旨在增強 Web 體驗,能讓用戶在訪問一個web的時候感覺在使用app一樣。 PWA可以看作是...
摘要:可以發(fā)送通知消息以再次吸引用戶并留住他們。在即時通訊等使用情形中,一條消息可將最多的有效負(fù)載傳送至客戶端應(yīng)用。瀏覽器的的消息推送主要依賴,服務(wù)端消息推送傳遞到,然后再由推送到客戶端。 引言 Progressive Web App, 簡稱 PWA,是提升 Web App 的體驗的一種新方法,能給用戶原生應(yīng)用的體驗。Service Worker 是 PWA 中的重要一部分。Service ...
摘要:再次修改控制臺輸出也就是說激活過程中的任何錯誤不影響被激活腦洞下新激活過程中說明頁面已經(jīng)沒有被其他控制了,所以事件回調(diào)函數(shù)的執(zhí)行失敗并不會影響被激活。 ServiceWorker生命周期 ServiceWorker本身是有狀態(tài)的(installing,installed,activating,activated,redundant),這些狀態(tài)構(gòu)成了ServiceWorker生命周期:s...
閱讀 2317·2021-11-22 12:01
閱讀 1995·2021-11-12 10:34
閱讀 4518·2021-09-22 15:47
閱讀 2832·2019-08-30 15:56
閱讀 2865·2019-08-30 15:53
閱讀 2404·2019-08-30 13:53
閱讀 3378·2019-08-29 15:35
閱讀 3126·2019-08-29 12:27