PWA初次體驗
? 前言:本示例不用安裝任何東西
部分資源來自網(wǎng)絡資源及PWA官網(wǎng)羊异,不要把PWA想象的太復雜,跟著示例走一下读慎,你行的。
PWA介紹
一個新的前端技術(shù)槐雾,PWA( 全稱:Progressive Web App )也就是說這是個漸進式的網(wǎng)頁應用程序夭委。
官網(wǎng):https://developers.google.com/web/progressive-web-apps/
是 Google 在 2015 年提出,2016年6月才推廣的項目募强。是結(jié)合了一系列現(xiàn)代Web技術(shù)的組合株灸,在網(wǎng)頁應用中實現(xiàn)和原生應用相近的用戶體驗。
官網(wǎng)上給出 PWA 的宣傳是 :Reliable( 可靠的 )擎值、Fast( 快速的 )慌烧、Engaging( 可參與的 )
Reliable:當用戶從手機主屏幕啟動時,不用考慮網(wǎng)絡的狀態(tài)是如何鸠儿,都可以立刻加載出 PWA屹蚊。
Fast:這一點應該都很熟悉了吧厕氨,站在用戶的角度來考慮,如果一個網(wǎng)頁加載速度有點長的話汹粤,那么我們會放棄瀏覽該網(wǎng)站命斧,所以 PWA 在這一點上做的很好,他的加載速度是很快的玄括。
Engaging: PWA 可以添加在用戶的主屏幕上冯丙,不用從應用商店進行下載,他們通過網(wǎng)絡應用程序 Manifest file 提供類似于 APP 的使用體驗( 在 Android 上可以設置全屏顯示哦遭京,由于 Safari 支持度的問題胃惜,所以在 IOS 上并不可以 ),并且還能進行 ”推送通知” 哪雕。
PWA關(guān)鍵技術(shù)
Service Worker(可以理解為服務工廠)
Manifest(應用清單)
Push Notification(推送通知)
Service Worker
以下用SW來表示
SW 是什么呢船殉?這個是離線緩存文件。我們 PWA 技術(shù)使用的就是它斯嚎!SW 是瀏覽器在后臺獨立于網(wǎng)頁運行的腳本利虫,它打開了通向不需要網(wǎng)頁或用戶交互的功能的大門,因為使用了它堡僻,才會有的那個 Reliable 特性吧糠惫,SW 作用于 瀏覽器于服務器之間,相當于一個代理服務器钉疫。
瀏覽器支持
順便帶一句:目前只能在 HTTPS 環(huán)境下才能使用SW硼讽,因為SW 的權(quán)利比較大,能夠直接截取和返回用戶的請求牲阁,所以要考慮一下安全性問題固阁。
image
事件機制
image
功能(還是比較逆天的)
后臺數(shù)據(jù)的同步
從其他域獲取資源請求
接受計算密集型數(shù)據(jù)的更新,多頁面共享該數(shù)據(jù)
客戶端編譯與依賴管理
后端服務的hook機制
根據(jù)URL模式城菊,自定義模板
性能優(yōu)化
消息推送
定時默認更新
地理圍欄
生命周期
image
Parsed ( 解析成功 ): 首次注冊 SW 時备燃,瀏覽器解決腳本并獲得入口點,如果解析成功凌唬,就可以訪問到 SW 注冊對象并齐,在這一點中我們需要在 HTML 頁面中添加一個判斷,判斷該瀏覽器是否支持 SW 客税。
Installing ( 正在安裝 ):SW 腳本解析完成之后况褪,瀏覽器會嘗試進行安裝,installing 中 install 事件被執(zhí)行霎挟,如果其中有 event.waitUntil ( ) 方法窝剖,則 installing 事件會一直等到該方法中的 Promise 完成之后才會成功麻掸,如果 Promise 被拒絕酥夭,則安裝失敗,SW會進入 Redundant( 廢棄 )狀態(tài)。
Installed / Waiting (安裝成功/等待中):如果安裝成功熬北,SW 將會進入這個狀態(tài)疙描。
Activating ( 正在激活 ):處于 waiting 狀態(tài)的 SW 發(fā)生以下情況,將會進入 activating 狀態(tài)中:
當前已無激活狀態(tài)的 worker 讶隐、 SW腳本中的 self.skipWaiting()方法被調(diào)用 ( ps: self 是 SW 中作用于全局的對象起胰,這個方法根據(jù)英文翻譯過來也能明白什么意思啦,跳過等待狀態(tài) )巫延、用戶已關(guān)閉 SW 作用域下的所有頁面效五,從而釋放了當前處于激活狀態(tài)的 worker、超出指定時間炉峰,從而釋放當前處于激活狀態(tài)的 worker
Activated ( 激活成功 ):該狀態(tài)畏妖,其成功接收了 document 全面控制的激活態(tài) worker 。
Redundant ( 廢棄 ):這個狀態(tài)的出現(xiàn)時有原因的疼阔,如果 installing 事件失敗或者 activating 事件失敗或者新的 SW 替換其成為激活態(tài) worker 戒劫。installing 事件失敗和 activating 事件失敗的信息我們可以在 Chrome 瀏覽器的 DevTools 中查看
一個很不錯的全面介紹sw的教程:https://www.villainhr.com/page/2017/01/08/Service%20Worker%20%E5%85%A8%E9%9D%A2%E8%BF%9B%E9%98%B6
Manifest
Web App Manifest 是一個 W3C 規(guī)范,它定義了一個基于 JSON 的 List 婆廊。Manifest 在 PWA 中的作用有:
?? ? ? ? ? ? ? ? ? 能夠?qū)⒛銥g覽的網(wǎng)頁添加到你的手機屏幕上
?? ? ? ? ? ? ? ? ? 在 Android 上能夠全屏啟動迅细,不顯示地址欄 ( 由于 Iphone 手機的瀏覽器是 Safari ,所以不支持哦)
?? ? ? ? ? ? ? ? ? 控制屏幕 橫屏 / 豎屏 展示
?? ? ? ? ? ? ? ? ? 定義啟動畫面
?? ? ? ? ? ? ? ? ? 可以設置你的應用啟動是從主屏幕啟動還是從 URL 啟動
?? ? ? ? ? ? ? ? ? 可以設置你添加屏幕上的應用程序圖標淘邻、名字茵典、圖標大小
Push Notification
Push 和 Notification 是兩個不同的功能,涉及到兩個 API 列荔。
?? Notification 是瀏覽器發(fā)出的通知消息敬尺。
?? Push 和 Notification 的關(guān)系,Push:服務器端將更新的信息傳遞給 SW 贴浙,Notification: SW 將更新的信息推送給用戶砂吞。
PWA示例
準備
我們先創(chuàng)建一個關(guān)于 PWA 的項目文件夾,
進入文件夾下我們準備一張 120x120的圖片一張崎溃,作為我們的應用程序圖標蜻直。
創(chuàng)建一個 index.html? 文件
創(chuàng)建一個 main.css 文件
創(chuàng)建一個 manifest.json 文件
創(chuàng)建一個 sw.js 文件
image
index.html
<!DOCTYPE html>Hello PWA
Hello PWA
// 檢測瀏覽器是否支持SWif(navigator.serviceWorker !=null){? ? navigator.serviceWorker.register('sw.js')? ? .then(function(registartion){console.log('支持sw:',registartion.scope)? ? })? }main.css
h3{color:#f00;}
manifest.json
short_name: “ " 用戶主屏幕上的應用名字
display : “standalone"? 設置啟動樣式,讓您的網(wǎng)絡應用隱藏瀏覽器的 URL 地址欄
start_url : “/“ 設置啟動網(wǎng)址袁串,如果不提供的話概而,默認是使用當前頁面
theme_color : “ “? 用來告知瀏覽器用什么顏色來為地址欄等 UI 元素著色
background_color: “ ” 設置啟動頁面的背景顏色
icons:””? 就是添加到主屏幕之后的圖標
{"name":"一個PWA示例","short_name":"PWA示例","start_url":"/index.html","display":"standalone","background_color":"#fff","theme_color":"#3eaf7c","icons": [? ? {"src":"/youhun.jpg","sizes":"120x120","type":"image/png"}? ],}
sw.js
看網(wǎng)上很多人都安裝的hs和ngrok去調(diào)試,在這里為了照顧新手我是直接引用的sw
處理靜態(tài)緩存囱修,首先定義需要緩存的路徑赎瑰,以及需要緩存的靜態(tài)文件的列表。
借助 SW 注冊完成安裝 SW 時破镰,抓取資源寫入緩存中餐曼。使用了一個方法那就是 self.skipWaiting( ) 压储,為了在頁面更新的過程當中,新的 SW 腳本能夠立刻激活和生效源譬。
importScripts("https://storage.googleapis.com/workbox-cdn/releases/3.1.0/workbox-sw.js");varcacheStorageKey ='minimal-pwa-1'varcacheList=['/','index.html','main.css','youhun.jpg']self.addEventListener('install',e =>{? e.waitUntil(? ? caches.open(cacheStorageKey)? ? .then(cache=>cache.addAll(cacheList))? ? .then(()=>self.skipWaiting())? )})
處理動態(tài)緩存集惋,我們監(jiān)聽 fetch 事件,在 caches 中去 match 事件的 request 踩娘,如果 response 不為空的話就返回 response 刮刑,最后返回 fetch 請求,在 fetch 事件中我們可以手動生成 response 返回給頁面养渴。
更新靜態(tài)資源雷绢,緩存的資源會跟隨著版本的更新會過期的,所以會根據(jù)緩存的字符串名稱清除舊緩存理卑。在新安裝的 SW 中通過調(diào)用 self.clients.claim( ) 取得頁面的控制權(quán)习寸,這樣之后打開頁面都會使用版本更新的緩存。舊的 SW 腳本不在控制著頁面之后會被停止傻工,也就是會進入 Redundant 期霞溪。
self.addEventListener('fetch',function(e){? e.respondWith(? ? caches.match(e.request).then(function(response){if(response !=null){returnresponse? ? ? }returnfetch(e.request.url)? ? })? )})self.addEventListener('activate',function(e){? e.waitUntil(//獲取所有cache名稱caches.keys().then(cacheNames=>{returnPromise.all(// 獲取所有不同于當前版本名稱cache下的內(nèi)容cacheNames.filter(cacheNames=>{returncacheNames !== cacheStorageKey? ? ? ? }).map(cacheNames=>{returncaches.delete(cacheNames)? ? ? ? })? ? ? )? ? }).then(()=>{returnself.clients.claim()? ? })? )})
部署
我們可以把當前pwa目錄的所有內(nèi)容都扔進服務器中,或者coding Pages和gitHub Pages也是可以的中捆,當然鸯匹,記得開啟https。在上變介紹過SW的權(quán)利比較大泄伪,為了安全性殴蓬,我們使用https協(xié)議來訪問。
試著訪問一下蟋滴,我們這里用的coding Pages并且綁定了自己的域名
打開 chrom 的調(diào)試工具染厅,打開 application ,點擊 service workers 之后我們會發(fā)現(xiàn) sw.js 腳本已經(jīng)存到了 SW 中 津函。
image
我們打開 Network 刷新頁面一下肖粮,看看,我們的頁面資源來自 SW 而不是其他的地方尔苦,在 Console 中也打印出了我們在 index.html 中判斷的語句涩馆,瀏覽器支持就會打印出這一句話。
image
接下來我們斷網(wǎng)操作允坚,在 Application 中給 Offline 打上對勾就行啦魂那。然后刷新頁面,我們?nèi)匀荒芸吹街暗捻撁娉硐睿蚓褪俏覀冊谏蠄D看到涯雅,他的資源是從 SW 上獲得到的。當我們第一次打開這個頁面的時候展运,Resopnse 對象被存到了 Cache Storage ( 定義在 SW 規(guī)范中 活逆,相關(guān)資料請同學們自行查詢啦 )中轻腺,我們看下圖:
image
通過存放到 Cache Storage 中,我們下次訪問的時候如果是弱網(wǎng)或者斷網(wǎng)的情況下划乖,就可以不走網(wǎng)絡請求,而直接就能將本地緩存的內(nèi)容展示給用戶挤土,優(yōu)化用戶的弱網(wǎng)及斷網(wǎng)體驗琴庵。
這個時候肯定會有同學在想,如果內(nèi)容更新了仰美,那么頁面展示的內(nèi)容是新內(nèi)容呢還是舊內(nèi)容呢迷殿?下面我們操作一下,打開 index.html 文件咖杂,我們在 body 中添加一個 p 標簽 庆寺,然后回到頁面刷新。
image
image
我們看到诉字,頁面上的內(nèi)容并沒有顯示出我剛剛添加的那個 p 標簽懦尝。這說明了,我們拿到的數(shù)據(jù)還是從 Cache Storage 中獲取到的壤圃,Cache Storage中的內(nèi)容并沒有更新陵霉,強制刷新也不行哦,那么我們怎么才能讓我剛剛添加的那個 p 標簽顯示出來呢伍绳。
我們打開 sw.js 腳本文件踊挠,我們修改一下 cacheStorageKey。
image
修改后冲杀,我們再次打開該網(wǎng)址效床,強制刷新下或者關(guān)掉瀏覽器重新打開。
頁面中出現(xiàn)了剛剛添加的P標簽权谁,我們再看一下 Cache Storage 中的緩存名字剩檀,已經(jīng)被修改。
image
總結(jié)
如果是使用coding或者gitHub提供的pages服務旺芽,則需要注意最好綁定下獨立域名谨朝。如果不綁定則注意下文件請求路徑即可。
研究PWA門檻不低甥绿,部署的服務器要求HTTPS字币,ServiceWorker涉及API眾多,需要單獨學習共缕,另外npm中也已經(jīng)有這個包了https://www.npmjs.com/package/web-pwa洗出,玩玩可以,真正部署到項目生產(chǎn)環(huán)境可能坑很多图谷,但有坑填坑翩活,不折騰還叫前端么