前端吹得這么火的PWA,你真的不來了解下嗎?
什么是漸進(jìn)式Web應(yīng)用(PWA)?
漸進(jìn)式Web應(yīng)用將網(wǎng)絡(luò)之長與應(yīng)用之長相結(jié)合,在用戶隨著時間的推移增進(jìn)與應(yīng)用的關(guān)系后,其功能會變得越來越強(qiáng)大。即使在網(wǎng)絡(luò)不良的情況下也能快速加載、能夠發(fā)送相關(guān)推送通知、具有桌面圖標(biāo),并且可采用全屏體驗的方式加載。
PWA具備以下特點:
漸進(jìn)式?- 適用于選用任何瀏覽器的所有用戶,因為它是以漸進(jìn)式增強(qiáng)作為核心宗旨來開發(fā)的。
自適應(yīng)?- 適合任何機(jī)型:桌面設(shè)備、移動設(shè)備、平板電腦或任何未來設(shè)備。
連接無關(guān)性?- 能夠借助于服務(wù)工作線程在離線或低質(zhì)量網(wǎng)絡(luò)狀況下工作。
類似應(yīng)用?- 由于是在 App Shell 模型基礎(chǔ)上開發(fā),因此具有應(yīng)用風(fēng)格的交互和導(dǎo)航,給用戶以應(yīng)用般的熟悉感。
持續(xù)更新?- 在服務(wù)工作線程更新進(jìn)程的作用下時刻保持最新狀態(tài)。
安全?- 通過 HTTPS 提供,以防止窺探和確保內(nèi)容不被篡改。
可發(fā)現(xiàn)?- W3C 清單和服務(wù)工作線程注冊作用域能夠讓搜索引擎找到它們,從而將其識別為“應(yīng)用”。
可再互動?- 通過推送通知之類的功能簡化了再互動。
可安裝?- 用戶可免去使用應(yīng)用商店的麻煩,直接將對其最有用的應(yīng)用“保留”在主屏幕上。
可鏈接?- 可通過網(wǎng)址輕松分享,無需復(fù)雜的安裝。
Service Workers(服務(wù)工作者)

漸進(jìn)式Web 應(yīng)用的定義中有部分是這樣說的:它必須支持離線工作。
由于允許 Web 應(yīng)用程序脫機(jī)工作的是 Service Worker,這意味著?Service Worker 是漸進(jìn)式 Web 應(yīng)用強(qiáng)制要求的部分。
Service Worker 是一個 JavaScript 文件,作為 Web 應(yīng)用和網(wǎng)絡(luò)之間的中間人。正因為如此,它可以提供緩存服務(wù),加速應(yīng)用程序渲染,并改善用戶體驗。
出于安全原因,只有 HTTPS 站點可以使用 Service Workers,這也是為什么必須通過 HTTPS 提供漸進(jìn)式 Web 應(yīng)用的原因之一。
用戶首次訪問應(yīng)用程序時,Service Workers 在設(shè)備上不可用。在首次訪問時,Web Worker 將被安裝,在隨后訪問網(wǎng)站的不同頁面時,Service Worker 將被調(diào)用。
ServiceWorker的強(qiáng)大在于它允許你控制如何處理來自頁面的網(wǎng)絡(luò)請求,它主要工作流程:注冊→安裝→提取→激活
注冊
// Checks if the browser supports Service workersif ('serviceWorker' in navigator) {?????//?registerServiceWorker.js?is?the?file?that?contains?the?install,?fetch?and?activativation?code.navigator.serviceWorker.register('registerServiceWorker.js').then(registration => {// Successful registrationconsole.log('Hooray. Registration successful, scope is:', registration.scope);}).catch(function(err) {// Failed registration, service worker won’t be installedconsole.log('Oops. Service worker could not be installed, error:', error);});}
registerServiceWorker.js?上面代碼塊中引用的文件通常包含安裝,獲取和激活代碼。
安裝
在安裝步驟中,您需要緩存一些靜態(tài)資源。如果所有文件都已成功緩存,則會安裝ServiceWorker。如果任何文件無法下載和緩存,則安裝步驟將失敗,ServiceWorker將不會被安裝和激活。
var CACHE_NAME = 'pwa-cache-v1';var urlsToCache = ['/','/styles/styles.css','/script/webpack-bundle.js'];self.addEventListener('install', event => {event.waitUntil(caches.open(CACHE_NAME).then(cache => {// Open a cache and cache our filesreturn cache.addAll(urlsToCache);}));});
urlsToCache是要緩存的文件的數(shù)組。通過cache.addAll()方法獲取它們,并將它們添加到緩存中。
提取
每當(dāng)用戶發(fā)出請求(導(dǎo)航到頁面或刷新頁面)時,都會觸發(fā)ServiceWoker監(jiān)聽的fetch事件,此方法會檢查請求并從ServiceWorker創(chuàng)建的緩存中查找命中的結(jié)果。
self.addEventListener('fetch', function(event) {event.respondWith(caches.match(event.request).then(function(response) {if (response) {return response;}return fetch(event.request);}));});
在上面的代碼塊中,fetch定義了事件,并在event.respondWith()函數(shù)中傳遞promise?
caches.match()方法查看請求并從ServiceWorker創(chuàng)建的緩存中查找命中的結(jié)果。
如果存在匹配的響應(yīng),則返回緩存的值。否則,返回從網(wǎng)絡(luò)請求的資源
激活
activate事件通常用于緩存管理,它在注冊后觸發(fā)。
self.addEventListener('activate', function(event) {var cacheWhitelist = ['pages-cache-v1', 'blog-posts-cache-v1'];event.waitUntil(// Get all the cache keys (cacheName)caches.keys().then(function(cacheNames) {return Promise.all(// Check all caches and delete old caches that are not whitelistedcacheNames.map(function(cacheName) {if (cacheWhitelist.indexOf(cacheName) === -1) {return caches.delete(cacheName);}}));}));});
上面的代碼塊是activate事件的示例。它遍歷服務(wù)工作程序中的所有緩存,并刪除緩存白名單中未定義的所有緩存。
在激活步驟之后,ServiceWorker將控制屬于其范圍的所有頁面。
ServiceWorker瀏覽器支持情況
CanIUse數(shù)據(jù)顯示:谷歌、safari、firefox、IE Edge、Opera最新版都已經(jīng)支持Service worker。

而從百度lavas(https://lavas.baidu.com/ready)上統(tǒng)計的數(shù)據(jù)來看,國產(chǎn)瀏覽器大部分都已支持這一特性。

應(yīng)用程序外殼(App Shell)

App Shell模型是一個簡單的設(shè)計概念,它不是Web API或框架,而是開發(fā)人員可以選擇遵循的設(shè)計方法。
使用App Shell模型,我們將應(yīng)用UI的外殼與其內(nèi)部的內(nèi)容分開,并且將它們單獨緩存。理想情況下,我們的App Shell會被緩存,以便在用戶訪問并在以后返回時盡快加載。理論上分別對shell和內(nèi)容加載可以提高用戶對應(yīng)用程序性能和可用性的感知。
應(yīng)用外殼的結(jié)構(gòu)分為應(yīng)用的核心基礎(chǔ)組件和承載數(shù)據(jù)的 UI。所有的 UI 和基礎(chǔ)組件都使用一個 service worker緩存在本地,因此在后續(xù)的加載中PWA應(yīng)用其他頁面時僅需要加載需要的數(shù)據(jù),而不是加載所有的內(nèi)容。
Web應(yīng)用程序清單(manifest)
Web應(yīng)用程序清單控制用戶從主屏幕啟動時看到的內(nèi)容,包括啟動畫面,主題顏色,圖標(biāo)等。
{"short_name": "PusherCoins","name": "PusherCoins","icons": [{"src": "favicon.ico","sizes": "192x192","type": "image/png"},{"src": "android-chrome-512x512.png","sizes": "512x512","type": "image/png"}],"start_url": "./index.html","display": "standalone","theme_color": "#000000","background_color": "#ffffff"}
manifest字段說明:
short_name:?用戶主屏幕上的文本段名稱name:?在網(wǎng)絡(luò)應(yīng)用安裝橫幅中使用的名稱icons:?當(dāng)用戶將您的網(wǎng)站添加到其主屏幕時,將使用這些圖標(biāo)。您還可以為瀏覽器定義一組圖標(biāo)以供使用。start_url:?指定當(dāng)用戶啟動從設(shè)備的應(yīng)用程序加載的URL,支持絕對或者相對URLdisplay:?定義瀏覽器的顯示模式。值可取是standalone(隱藏瀏覽器UI),fullscreen,browser(網(wǎng)頁瀏覽模式),或minimal-ui。theme_color:?定義了應(yīng)用程序的默認(rèn)主題顏色,這會影響操作系統(tǒng)顯示應(yīng)用程序的方式background_color:?定義了Web應(yīng)用程序預(yù)期的背景色。
后臺同步(Background Sync)
后臺同步是一種Web API,可以將操作推遲直到用戶具有穩(wěn)定網(wǎng)絡(luò)連接。這對于確保實際發(fā)送用戶想要發(fā)送的內(nèi)容非常有用,即使在失去網(wǎng)絡(luò)連接之后也是如此。
例如,后臺同步在聊天應(yīng)用程序中非常有用。你可能已經(jīng)遇到過在發(fā)送消息后連接錯誤或根本沒有連接的情況,通過后臺同步功能,它仍然會在網(wǎng)絡(luò)重連之后繼續(xù)傳遞消息。
在PWA中實現(xiàn)后臺同步非常簡單。以下面的代碼為例:
// Register your service worker:navigator.serviceWorker.register('/sw.js');// Then later, request a one-off sync:navigator.serviceWorker.ready.then(function(swRegistration) {return swRegistration.sync.register('myFirstSync');});
在上面的代碼中,ServiceWorker已注冊,然后我們請求一次性同步,其名稱為myFirstSync。然后我們在/sw.js以下地方監(jiān)聽sync事件:
self.addEventListener('sync', function(event) {if (event.tag == 'myFirstSync') {event.waitUntil(doSomeStuff());}});
在上面的代碼塊中,doSomeStuff()應(yīng)該返回一個promise,指示它正在嘗試做的任何事情的成功/失敗。如果滿足,則同步完成。如果失敗,將重試同步過程。
PWA開發(fā)入門視頻
視頻時長接近40分鐘,帶你快速入門PWA的開發(fā)
PWA相關(guān)資源
Lavas,基于 Vue.js 的 PWA 解決方案:https://lavas.baidu.com/
你的第一個PWA應(yīng)用:https://developers.google.com/web/fundamentals/codelabs/your-first-pwapp/
Lighthouse,谷歌插件,PWA性能檢測:https://chrome.google.com/webstore/detail/lighthouse/blipmdconlkpinefehnmjammfjpmpbjk?hl=en
如果你喜歡探討技術(shù),或者對本文有任何的意見或建議,非常歡迎加魚頭微信好友一起探討,當(dāng)然,魚頭也非常希望能跟你一起聊生活,聊愛好,談天說地。魚頭的微信號是:krisChans95 也可以掃碼關(guān)注公眾號,訂閱更多精彩內(nèi)容。
