一、什么是PWA應(yīng)用?
1、PWA簡介
? 漸進(jìn)式Web應(yīng)用(Progressive Web App),簡稱PWA,是 Google 在 2015 年提出的一種使用web平臺技術(shù)構(gòu)建的應(yīng)用程序,官方認(rèn)為其核心在于Reliable
(可靠的)、Fast
(快速的)、Engaging
(可參與的),結(jié)合了web網(wǎng)站程序和原生應(yīng)用程序兩者的優(yōu)點,可以帶給用戶更佳的使用體驗。
? PWA既能像網(wǎng)站一樣,通過一套代碼在多個平臺運行,而且可以通過瀏覽器進(jìn)行訪問,并通過Url鏈接進(jìn)行分享。又能像原生應(yīng)用一樣,通過應(yīng)用商店或網(wǎng)頁安裝在設(shè)備上,安裝之后可以通過圖標(biāo)訪問,作為一個獨立的應(yīng)用程序被啟動;而且即使脫離網(wǎng)絡(luò),也可以通過應(yīng)用緩存訪問到部分頁面和數(shù)據(jù)。
? 但需要注意的是,當(dāng)PWA應(yīng)用通過安裝在設(shè)備上的圖標(biāo)打開時,雖然從外觀上看來像是一個原生的應(yīng)用程序,但從技術(shù)角度來看,其仍屬于網(wǎng)站范疇,所以仍需要一個瀏覽器引擎來解析和運行,為其提供正常運行的環(huán)境。因此其原理類似于打開了一個單獨的、自定義窗口內(nèi)容的瀏覽器窗口。
? PWA不僅是一種技術(shù),更代表了一種Web網(wǎng)站的開發(fā)理念,如果一個網(wǎng)站程序?qū)崿F(xiàn)了可安裝、可離線等多種特定功能,我們就可以將其視為一個PWA應(yīng)用。目前國內(nèi)支持PWA的網(wǎng)站有:微博、語雀等等。
2、PWA特點
? 原生應(yīng)用程序代表了最佳的功能,因為其與操作系統(tǒng)深入結(jié)合,擁有易于訪問、可離線、操作系統(tǒng)集成等優(yōu)點。 Web 網(wǎng)站程序則代表了最廣的范圍,因為其以瀏覽器為基礎(chǔ),擁有跨平臺、無需下載、易于更新部署等優(yōu)點。而PWA 則處于原生應(yīng)用程序功能和 Web 網(wǎng)站程序范圍的交叉點,是兩者的結(jié)合體,主要擁有以下幾種特點:
? ① 跨平臺: PWA應(yīng)用只需開發(fā)者書寫一套代碼,就可以在不同操作平臺上運行,而且PWA應(yīng)用采取漸進(jìn)式增強的理念,其核心功能可以在任何瀏覽器上正常運行,其余強大的功能則需要依賴于瀏覽器對PWA特性的支持,根據(jù)瀏覽器的支持性,逐步升級體驗。
? ② 可安裝: PWA應(yīng)用可以添加到主屏幕或應(yīng)用程序菜單中,實現(xiàn)類似原生應(yīng)用的圖標(biāo)入口,點擊圖標(biāo),作為一個獨立應(yīng)用被啟動,用戶可以更方便地訪問應(yīng)用。也可以將程序打包并上傳各個應(yīng)用商店,讓用戶通過應(yīng)用商店安裝網(wǎng)站應(yīng)用。
? ③ 離線訪問: PWA應(yīng)用具備離線訪問的能力,它們可以緩存應(yīng)用的核心資源,使得用戶可以在沒有網(wǎng)絡(luò)連接的情況下繼續(xù)訪問應(yīng)用,查看到部分頁面和數(shù)據(jù),提供基本的功能,并在網(wǎng)絡(luò)恢復(fù)時更新緩存。
? ④ 推送通知: PWA應(yīng)用可以主動發(fā)送推送通知給用戶,使得應(yīng)用可以及時通知用戶有關(guān)重要更新、新消息或其他關(guān)鍵信息,類似于原生應(yīng)用的通知功能。
? ⑤ 快速加載: PWA應(yīng)用使用Service Workers來緩存資源并提供離線體驗,這也使得應(yīng)用可以更快地加載和響應(yīng)用戶操作。
? ⑥ 可搜索: PWA應(yīng)用可以通過搜索引擎被發(fā)現(xiàn),而且可以通過url鏈接進(jìn)行分享。
? ⑦ 熱更新: PWA應(yīng)用中的部分內(nèi)容發(fā)生更新時,可在聯(lián)網(wǎng)后自動進(jìn)行局部熱更新,確保用戶能用到最新的應(yīng)用程序,而無需像原生應(yīng)用一樣,重新下載安裝客戶端。
? 結(jié)合官方提出的Reliable
(可靠的)、Fast
(快速的)、Engaging
(可參與的)三個核心,我認(rèn)為跨平臺、離線訪問體現(xiàn)了Reliable
(可靠的),無論是在低版本瀏覽器還是無網(wǎng)絡(luò)的情況下,PWA都可以展示基本功能;快速加載、熱更新則體現(xiàn)了Fast
(快速的),利用緩存和自動更新,減少重復(fù)數(shù)據(jù)加載,提升響應(yīng)速度;可安裝和推送通知則體現(xiàn)了Engaging
(可參與的),可安裝在設(shè)備上,并向用戶推送通知。
3、適用場景
? 地圖導(dǎo)航、資料文檔、博客筆記等等。
二、PWA的核心技術(shù)是什么?
? PWA的實現(xiàn)依賴于多種技術(shù)實現(xiàn),其中最核心的技術(shù)為Service Worker
、Web App Manifest
和Push Notification
。
1、Service Worker
? Service Worker是一個獨立于網(wǎng)頁線程的腳本,無權(quán)訪問頁面的DOM結(jié)構(gòu),充當(dāng)了網(wǎng)站和瀏覽器之間的代理服務(wù)器,每個PWA應(yīng)用都只能注冊一個Service Worker,其在PWA中主要用來實現(xiàn)離線訪問、緩存資源、推送通知等功能,當(dāng)然除此之外,它還具有很多其他功能,在這我們就不展開講述了。
? 在網(wǎng)絡(luò)正常時,當(dāng)PWA應(yīng)用請求Service Worker范圍內(nèi)的資源時,Service Worker會攔截該請求,并充當(dāng)網(wǎng)絡(luò)代理,然后它可以決定是從緩存中獲取數(shù)據(jù)還是從服務(wù)器中獲取數(shù)據(jù)。如果是從服務(wù)器中獲取數(shù)據(jù),Service Worker會緩存請求的數(shù)據(jù),等到離線訪問時,返回緩存的數(shù)據(jù),使得PWA應(yīng)用可以在離線狀態(tài)下運行,并且可以利用緩存提升應(yīng)用的加載速度。
? 由于Service Worker權(quán)利太大,能夠直接截取并返回用戶的請求,處于安全性考慮,目前僅支持在HTTPS或本地環(huán)境的安全環(huán)境下使用。
? Service Worker的瀏覽器兼容性如下圖:
如何為PWA注冊Service Worker?
? 在Service Worker控制頁面之前,必須在PWA應(yīng)用中注冊Service Worker服務(wù)。這意味著,在用戶第一次訪問PWA應(yīng)用時,頁面還并未受到Service Worker的控制,也就無法實現(xiàn)離線訪問等功能。
? 注冊Service Worker時,我們只需先判斷瀏覽器是是否支持相關(guān)的API,如果支持則直接通過navigator.serviceWorker.register(url)
進(jìn)行注冊即可,參數(shù)url
表示具體Service Worker邏輯代碼文件的路徑。
// 這是頁面中唯一與Service Worker有關(guān)的代碼
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js')
.then(registration => {
console.log('Service Worker 注冊成功!', registration);
})
.catch(error => {
console.log('Service Worker 注冊失?。?, error);
});
}
? 如果想要查看Service Worker是否已經(jīng)注冊并正常運行,以Chrome瀏覽器為例,我們可以通過F12開發(fā)者工具中的Application,然后選中左側(cè)的Service Workers ,如果右側(cè)展示的信息中的Status
中顯示activity
則表示已經(jīng)注冊并正常運行。
? 如果想要在移動端頁面檢查是否已經(jīng)注冊并正常運行,也只能通過連接電腦調(diào)試的方法來查看,具體可查看該文檔:tools-and-debug。
Service Worker的作用范圍怎么確定?
? Service Worker在注冊時引入的具體邏輯文件所在文件夾決定了其作用范圍,例如:
navigator.serviceWorker.register("example.com/my-pwa/serviceworker.js");
? 則該Service Worker的作用范圍在my-pwa
文件夾下的任何文件,如: example.com/my-pwa/index.html
等等。
? 為了實現(xiàn)Service Worker在PWA應(yīng)用中的作用最大化,推薦將具體邏輯文件設(shè)置在PWA應(yīng)用程序的根目錄下,因為這樣可以攔截到PWA應(yīng)用中的所有請求。
Service Worker的生命周期分為哪些階段?
? Service Worker 的生命周期從注冊 Service Worker 開始,也就是前文所說的register()
方法,調(diào)用該方法時,就會發(fā)生注冊行為。該生命周期階段并沒有對應(yīng)的事件,然后我們可以通過register()
方法的.then()
來判斷是否注冊成功。
① Registration(注冊)
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js')
.then(registration => {
console.log('Service Worker 注冊成功!', registration);
})
.catch(error => {
console.log('Service Worker 注冊失?。?, error);
});
}
? 然后瀏覽器開始下載并安裝 Service Worker 文件,安裝成功后,則會觸發(fā)install
事件,在整個生命周期中,install
事件僅會觸發(fā)這一次。開發(fā)者通常會在此事件中進(jìn)行初始化,緩存一些靜態(tài)資源,以備離線時訪問。
② Installation(安裝)
// 安裝階段
self.addEventListener('install', function(event) {
event.waitUntil(
// 向緩存中存儲基本數(shù)據(jù)
caches.open('cache-name').then(function(cache) {
return cache.addAll([
'/path/to/resource1',
'/path/to/resource2',
// ...
]);
})
);
});
? 在Service Worker中,我們需要通過全局對象self
才能監(jiān)聽各個生命周期事件。在waitUntil()
方法執(zhí)行結(jié)束之前,Service Worker不會結(jié)束安裝狀態(tài),必須等待其內(nèi)部代碼執(zhí)行結(jié)束之后,才會進(jìn)入到下一個生命周期。caches
對象是限制在Service Worker 生命周期內(nèi)使用的特殊對象,用于實現(xiàn)數(shù)據(jù)的緩存。
③ Activation(激活)
? 當(dāng)Service Worker安裝完成后,并不會立即進(jìn)入激活狀態(tài),為了不影響當(dāng)前正在訪問的頁面,此時Service Worker 并沒有控制當(dāng)前頁面。所以要等到當(dāng)前頁面關(guān)閉,且再次加載該頁面時,Service Worker才會進(jìn)入激活狀態(tài),觸發(fā)activate
事件,開始控制網(wǎng)頁的請求和緩存。在此階段,開發(fā)者通常會進(jìn)行清理舊的緩存、處理更新邏輯等操作,因為瀏覽器的緩存空間是有限的。
// Service Worker激活成功后
self.addEventListener('activate', function(event) {
event.waitUntil(
// 對緩存中的數(shù)據(jù)進(jìn)行處理
caches.keys().then(function(cacheNames) {
return Promise.all(
// 只保留符合要求的數(shù)據(jù) 刪除不需要的舊數(shù)據(jù)
cacheNames.filter(function(cacheName) {
return cacheName !== 'cache-name';
}).map(function(cacheName) {
return caches.delete(cacheName);
})
);
})
);
});
? 在waitUntil()
方法執(zhí)行結(jié)束之前,Service Worker不會進(jìn)入下個狀態(tài),然后可以通過caches
對象,對緩存的數(shù)據(jù)進(jìn)行操作。
? 還有要注意的一點是,Service Worker 進(jìn)入激活狀態(tài)后,它會一直保持激活狀態(tài),除非被手動注銷或者被新的 Service Worker 腳本取代。
④ Update(更新)
? 瀏覽器會周期性的檢測當(dāng)前應(yīng)用的Service Worker是否有更新,當(dāng)檢測到Server Worker 腳本文件發(fā)生更新時,會在后臺下載新的腳本,并觸發(fā)更新流程。更新流程與安裝流程類似,需要經(jīng)歷下載、安裝、激活三個階段。下載完成之后,會立即進(jìn)行安裝,但是安裝完成之后,默認(rèn)并不會立即激活,而且進(jìn)入等待狀態(tài)。因為同一時間只能有一個版本的 Service Worker處于Activation
狀態(tài)。只有當(dāng)舊版本的Service Worker控制的所有頁面都被關(guān)閉,然后用戶再重新訪問這些頁面時,新的Service Worker才會被激活并接管舊版本所有頁面的控制權(quán)。
? 我們也可以通過skipWaiting()
方法來強制激活等待中 Service Worker,使其取代舊版 Service Worker,獲得頁面的控制權(quán)。該方法只有在存在等待狀態(tài)的 Service Worker時,調(diào)用才會有意義,所以通常都在install
事件中執(zhí)行調(diào)用。
// 新版Service Worker的install事件
self.addEventListener("install", (event) => {
// 安裝好后 調(diào)用skipWaiting() 使其立即激活
// skipWaiting() 返回一個 promise,但完全可以忽略它
self.skipWaiting();
// 然后執(zhí)行 service worker 安裝所需的緩存數(shù)據(jù)等其他操作
e.waitUntil(
(async () => {
const cache = await caches.open(cacheName);
await cache.addAll(contentToCache);
})(),
);
});
⑤ Termination(終止)
? 當(dāng)Service Worker被手動注銷,或被新版本Service Worker取代后,就會進(jìn)入終止階段,它將不再控制頁面的請求,并釋放相應(yīng)的資源。即使不被注銷或者取代,Service Worker也不會無限期的存活,各大瀏覽器的處理邏輯不同,但在激活一段時間后,Service Worker就會被終止。終止之后,需要重新注冊,才能繼續(xù)運行。
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js')
.then(registration => {
console.log('Service Worker 注冊成功!', registration);
// 手動注銷Service Worker
registration.unregister().then(function (boolean) {
if(boolean) {
console.log('Service Worker 注銷成功!')
}
});
})
.catch(error => {
console.log('Service Worker 注冊失?。?, error);
});
}
⑥ Fetch(請求)
? Service Worker 還提供了一個fetch
事件,每當(dāng)Service Worker控制的頁面中,發(fā)出fetch
請求或者h(yuǎn)tml、css、js等資源請求時,都會觸發(fā)該事件,我們可以在此階段攔截請求并結(jié)合緩存使用自定義響應(yīng)來響應(yīng)請求。注意:ajax
請求不會觸發(fā)該事件。
? 通常當(dāng)請求的資源存在緩存時,我們都會從緩存中獲取資源而不是從服務(wù)器獲取。如果緩存中沒有,那我們會使用另一個請求從服務(wù)器獲取資源,并將資源存儲在緩存中,以便下次請求或離線請求時使用。
self.addEventListener("fetch", (e) => {
e.respondWith(
(async () => {
// 從緩存中獲取資源
const r = await caches.match(e.request);
console.log(`Service Worker正在請求資源: ${e.request.url}`);
if (r) {
// 如果緩存中存在資源 則直接返回緩存中的資源
return r;
}
// 如果緩存中沒有 則去服務(wù)器請求資源
const response = await fetch(e.request);
const cache = await caches.open(cacheName);
console.log(`Service Worker 緩存新資源: ${e.request.url}`);
// 將請求的資源存儲到緩存中
cache.put(e.request, response.clone());
// 將請求結(jié)果緩存
return response;
})(),
);
});
? 該fetch
事件的事件對象event
中包含了一個respondWith()
方法,該方法可以阻止瀏覽器默認(rèn)的fetch
請求操作,并允許自定義請求的response
,更多信息請查看:FetchEvent.respondWith()。
2、Web App Manifest
? Web App Manifest(Web應(yīng)用清單),是一個遵守W3C規(guī)范的JSON文件,用來定義PWA安裝的客戶端在設(shè)備上應(yīng)該如何顯示和運行,例如應(yīng)用的名稱、圖標(biāo)、啟動方式等等,該文件是實現(xiàn)PWA所必需的。通過該文件,用戶可將PWA應(yīng)用安裝到用戶的主屏幕上,使其更像一個原生應(yīng)用的客戶端。
? 該文件中可定義的應(yīng)用信息很多,其中比較常用的有以下幾條:
① name
? 該字段定義PWA應(yīng)用的全名,是Web App Manifes中必須的一個基本字段。該名稱一般會顯示為應(yīng)用商店的應(yīng)用名稱,也會在應(yīng)用啟動時顯示在標(biāo)題欄中。
"name": "學(xué)科網(wǎng)PWA示例"
② short_name
? 該字段定義PWA應(yīng)用的簡稱,盡量控制在12個字符以內(nèi),當(dāng)應(yīng)用程序被安裝在桌面上時,由于空間有限,通常就會顯示該簡稱,但具體展示name
還是short_name
可能因設(shè)備、瀏覽器或操作系統(tǒng)而有所不同,例如:在macos系統(tǒng)中,統(tǒng)一展示name
字段。
"short_name": "PWA示例"
③ icons
? 該字段定義了應(yīng)用程序安裝在桌面上的圖標(biāo),屬性值為一個數(shù)組,數(shù)組元素為一個對象,對象中包含src
、sizes
、type
三個屬性,分別代表圖標(biāo)地址、圖標(biāo)的尺寸和圖標(biāo)的MIME類型。
-
src
:指定了圖標(biāo)文件的位置,字段值可以是相對于manifest
文件的相對URL,或者是一個絕對的網(wǎng)絡(luò)URL。 -
sizes
:指明了圖標(biāo)的尺寸,以寬×高
的形式指定了圖標(biāo)的寬高,單位默認(rèn)為px
,目前設(shè)備適配性最好的圖標(biāo)尺寸為512×512
。 -
type
:指明了圖標(biāo)的MIME
媒體類型,幫助瀏覽器在選擇合適的圖標(biāo)文件,例如:image/png
、image/jpeg
等等。
? 該字段屬性值數(shù)組至少需要定義一個圖標(biāo)元素,也可以定義多個不同格式的圖標(biāo)元素,從而為用戶提供最佳的圖標(biāo)效果。每個瀏覽器都會根據(jù)其需要和所安裝的操作系統(tǒng)選擇其中最接近其所需的規(guī)范的某個圖標(biāo)。圖標(biāo)選擇規(guī)則很多,主要有尺寸匹配、類型匹配、設(shè)備類型匹配等規(guī)則。
"icons": [
{
"src": "icons/512.png",
"type": "image/png",
"sizes": "512x512"
},
{
"src": "icons/1024.png",
"type": "image/png",
"sizes": "1024x1024"
}
]
④ start_url
? 該字段定義PWA應(yīng)用的起始URL,用戶點擊圖標(biāo)打開程序時,將會加載這個URL所對應(yīng)的頁面,可以是相對于manifest文件的相對路徑,也可以是一個絕對路徑。推薦使用絕對路徑,如果PWA應(yīng)用的主頁是網(wǎng)站的根目錄,那么將該字段設(shè)置為/
即可。如果沒有設(shè)置該字段,則默認(rèn)將安裝PWA應(yīng)用時的URL作為該字段的值。
"start_url": "./index.html"
⑤ display
? 該字段定義了PWA應(yīng)用的打開方式,字段值有以下四種:
-
standalone
(推薦):應(yīng)用將以獨立窗口打開,類似于原生應(yīng)用程序,沒有導(dǎo)航欄等瀏覽器功能。
-
fullscreen
:應(yīng)用將以全屏模式打開,隱藏瀏覽器的地址欄和工具欄。由于電腦操作系統(tǒng)的限制,該字段值表現(xiàn)效果與standalone
一致。 -
minimal-ui
:應(yīng)用將獨立窗口打開,但保留了一部分瀏覽器的導(dǎo)航功能,如后退、刷新功能等。
-
browser
:應(yīng)用將以常規(guī)瀏覽器網(wǎng)頁的形式打開,類似于設(shè)置了一個網(wǎng)頁的快捷方式。但是由于電腦操作系統(tǒng)的限制,該字段值表現(xiàn)效果與standalone
一致。"display": "standalone"
⑥ id
? 該字段用于作為PWA應(yīng)用的唯一標(biāo)識,如果未設(shè)置,則默認(rèn)以start_url
的值為字段值。
"id": "xkw-pwa"
⑦ background_color
? 該字段定義了PWA應(yīng)用窗口打開后且樣式表加載完成之前的窗口背景色,字段值支持關(guān)鍵字(red、green等)、十六進(jìn)制色值(#FFFFFF、#CCCCC等)和RGB色值(rgb(255,255,255)等),但不建議使用rgba()
等帶有透明度的顏色,因為各個瀏覽器的展示效果可能大相徑庭。但是目前iOS 和 iPadOS 上的 Safari 以及部分桌面瀏覽器目前會忽略此字段。
"background_color": "#000000",
⑧ theme_color
? 該字段定義了PWA應(yīng)用的窗口主題色,將會影響窗口工具欄、頭部標(biāo)題欄等區(qū)域的顏色,段值支持關(guān)鍵字(red、green等)、十六進(jìn)制色值(#FFFFFF、#CCCCC等)和RGB色值(255,255,255等)。但是該屬性會被<meta name="theme-color" content="#ccc">
標(biāo)簽設(shè)置的主題色所覆蓋。
"theme_color": "#3880FF"
⑨ 其他屬性
? 。。。
3、Push Notification
? Push
和 Notification
是兩個獨立的API,Push
用來接收服務(wù)器推送的信息,Notification
用來向用戶推送信息。兩者都需要在 Service Worker 內(nèi)調(diào)用運行。
? 具體可查看:Push Notification
三、如何開發(fā)一個PWA應(yīng)用Demo?
1、創(chuàng)建一個demo文件夾,用來存儲相關(guān)文件
2、創(chuàng)建manifest.json文件,設(shè)置PWA應(yīng)用信息
{
"name": "豬豬俠的PWA示例",
"short_name": "PWA示例",
"start_url": "/index.html",
"display": "standalone",
"background_color": "red",
"theme_color": "#ccc",
"icons": [
{
"src": "/icons/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/icons/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}
3、創(chuàng)建icons文件夾,存儲PWA應(yīng)用圖標(biāo)文件
? 存儲以下兩個圖標(biāo)文件:
4、創(chuàng)建main.css文件,設(shè)置頁面樣式
h3 {
color: red;
}
5、創(chuàng)建sw.js文件,設(shè)置Service Worker相關(guān)邏輯
? 這里我們只需要直接書寫Service Worker的處理邏輯即可:
// 緩存的key值,用于區(qū)別新舊版本緩存
var cacheStorageKey = 'minimal-pwa-2'
// 設(shè)置初始需要緩存的文件
var cacheList = [
'/',
'index.html',
'main.css',
'/icons/android-chrome-512x512.png'
]
// 監(jiān)聽安裝事件 并在此階段 緩存基本資源
self.addEventListener('install', e => {
e.waitUntil(
caches.open(cacheStorageKey)
.then(
// 緩存基本資源
cache => cache.addAll(cacheList)
)
.then(() =>
// 當(dāng)腳本更新時 使新版Service Worker強制進(jìn)入activate狀態(tài)
self.skipWaiting()
)
)
})
// 監(jiān)聽fetch請求事件
self.addEventListener('fetch', function (e) {
// 攔截相關(guān)請求
e.respondWith(
// 如果緩存中已經(jīng)有請求的數(shù)據(jù)就終止請求 直接返回緩存數(shù)據(jù)
caches.match(e.request).then(async function (response) {
if (response != null) {
return response
}
// 否則就重新向服務(wù)端請求
const res = await fetch(e.request)
// 這塊需要結(jié)合具體業(yè)務(wù)具體分析 我這里的示例邏輯是無腦全部緩存
// 請求成功后將請求的資源緩存起來 后續(xù)請求直接走緩存
const cache = await caches.open(cacheStorageKey)
cache.put(e.request, res.clone())
// 將請求的資源返回給頁面。
return res;
})
)
})
// 監(jiān)聽激活事件
self.addEventListener('activate', function (e) {
e.waitUntil(
//獲取所有cache名稱
caches.keys().then(cacheNames => {
return Promise.all(
// 獲取緩存中所有不屬于當(dāng)前版本cachekey下的內(nèi)容
cacheNames.filter(cacheNames => {
return cacheNames !== cacheStorageKey
}).map(cacheNames => {
// 刪除不屬于當(dāng)前版本的cache緩存數(shù)據(jù)
return caches.delete(cacheNames)
})
)
}).then(() => {
// 無須刷新頁面 即可使新版server worker接管當(dāng)前頁面
return self.clients.claim()
})
)
})
6、創(chuàng)建主文件index.html,設(shè)置頁面DOM,并引用各類資源
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello PWA</title>
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<link rel="stylesheet" href="main.css">
<link rel="manifest" href="manifest.json">
</head>
<body>
<h3>Hello 豬豬俠的PWA</h3>
</body>
<script>
// 檢測瀏覽器是否支持SW
if ('serviceWorker' in navigator) {
// 為當(dāng)前頁面注冊Service Worker
navigator.serviceWorker.register('./sw.js')
.then(function (registartion) {
console.log('當(dāng)前瀏覽器支持sw:', registartion.scope);
console.log('Service Worker注冊成功', registartion);
})
}
</script>
</html>
7、部署到服務(wù)器上(https) 或在本地環(huán)境使用
以本地環(huán)境為例,使用VSCode作為輔助工具:
① 在VSCode中,右鍵選中index.html文件,選中Open with live Server
選項,運行頁面:
② F12控制臺,查看Service Worker是否注冊成功:
③ 然后點擊Application,選中左側(cè)Service Workers,查看sw腳本是否正常運行:
④ 點擊左側(cè)Cache Storage,選中我們定義的cacheStorageKey-當(dāng)前域名地址,查看初始資源(sw.js文件中定義的cacheList數(shù)組中的資源)是否被緩存:
⑤ 點擊Network,選中All,刷新頁面,查看請求資源情況:
⑥ 經(jīng)過上次刷新,所有相關(guān)資源已被緩存,再次刷新頁面,所有資源都將經(jīng)過Service Worker之后,從緩存中獲取:
⑦ 通過選中NetWork中的Offline選項切斷網(wǎng)絡(luò),查看在無網(wǎng)絡(luò)時,頁面是否能利用緩存正常顯示:
⑧ 點擊右上角的下載按鈕,安裝PWA應(yīng)用到設(shè)備上:
⑨ 以macos系統(tǒng)為例,PWA應(yīng)用安裝后,會自動打開,并桌面端入口安裝到應(yīng)用啟動臺中,查看打開后的頁面:
⑩ F12控制臺,重復(fù)②~⑦的操作,驗證在桌面端打開時,Service Worker 能否正常運行。
? 下載安裝的PWA應(yīng)用,需要通過右上角的功能區(qū),進(jìn)行卸載:
? 如果我們本地修改了項目文件的內(nèi)容,直接刷新或者關(guān)閉頁面再打開,是看不到更新的內(nèi)容的,因為都是直接從緩存中獲取相關(guān)數(shù)據(jù),而且關(guān)閉頁面或瀏覽器后Service Worker腳本依舊在后臺執(zhí)行,再次打開訪問時,依舊是從緩存中獲取數(shù)據(jù)。想要頁面顯示最新的內(nèi)容需要先注銷掉舊的的腳本,然后讓新腳本取代舊腳本即可,在瀏覽器開發(fā)工具的Application中我們可以直接注銷Service Worker腳本,然后再刷新頁面即可:
? 其他操作。。。
四、相關(guān)資料
PWA谷歌文檔
PWA的MDN文檔
Service Worker
Service Worker 生命周期
Web App Manifes文章來源:http://www.zghlxwxcb.cn/news/detail-833509.html
參考博客文章來源地址http://www.zghlxwxcb.cn/news/detail-833509.html
到了這里,關(guān)于前端PWA應(yīng)用的相關(guān)知識和基礎(chǔ)Demo的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!