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