本文由 IMWeb 團隊成員 lq 首發。點擊閱讀原文查看 IMWeb 社區更多精彩文章。html
注:本文須要有必定的 PWA 基礎前端
要知道一個東西是什麼,咱們一般能夠從它的名字入手webpack
所以咱們看下 PWA 的全稱是: Progressive Web Appweb
回答 what 這種問題,重點在於名詞,所以 PWA 是一個 APP,一個獨立的、加強的、Web 實現的 APP瀏覽器
要達到這樣的目的,PWA 提供了一系列的技術 & 標準,以下圖所示:緩存
具體每一項技術是什麼就再也不贅述了,感興趣的同窗自行網上搜索! 下面有一個簡單的 demo 能夠簡單體會一下:性能優化
之後咱們的 web 站點能夠像 app 同樣,這難道不是一個使人興奮的事情嗎?架構
因此 PWA 是值得咱們前端開發者一直關注的技術!併發
按照目前的兼容性和環境來看,你們應用最多的仍是 Service Worker,所以接下來咱們也是把重點放在 SW 上面app
那什麼是 Service Worker ?
你們都知道就不賣關子了,其實就是一個 Cache
說到 Cache,就必定會想到性能優化了,請看咱們的第二部分
如何利用 Cache 來進行優化?這個基本套路應該無人不知了:
那麼首次加載怎麼辦呢?首次加載是沒有緩存資源的,因此會走到線上,因此等於沒有任何優化
答案就是 Cache 的第二種經常使用技巧: precache(預加載)
預加載的意思就是在某個地方或特定時機預先把須要用到的資源加載並緩存
咱們的作法以下圖所示:
構建的時候,把整個項目用到的資源輸出到一個 list 中,而後 inline 到 sw.js 裏面
當 sw install 時,就會把這個 list 的資源所有請求並進行緩存
這樣作的結果就是,不管用戶第一次進入到咱們站點的哪一個頁面,咱們都會把整個站點全部的資源都加載回來並緩存
當用戶跳轉另一個頁面的時候,Cache 裏面就有相應的資源了!
這是咱們輔導課堂頁面接入 sw 以後的首屏優化效果:
除了靜態資源以外,咱們還能緩存其餘的內容嗎?
答案確定是能夠的,咱們還能夠緩存 cgi 數據!
緩存 cgi 數據的流程和緩存靜態資源的流程主要有2個差異,上圖標紅的地方:
須要添加一個開關功能,由於不是全部 cgi 都須要緩存的!
頁面須要展現最新的數據,所以在返回緩存結果以後,還須要請求線上最新的數據,更新緩存,而且返回給頁面展現,也就是說頁面須要展現2次
頁面展現2次須要考慮頁面跳動的體驗問題,選擇權在於業務自己!
這是咱們輔導上課頁接入該功能後的首屏優化效果:
動態數據緩存是否有意義還須要額外的邏輯來判斷,這塊暫時是沒有作的,後續會補上相關統計
還能緩存什麼?咱們想到了直出的 html
這裏就不展開講了,由於咱們的 jax 同窗已經分享了一篇優秀的文章《企鵝輔導課程詳情頁毫秒開的祕密 - PWA 直出》,能夠去看看哈~
PWA 與離線包本質上是同樣的,都是離線緩存
正好,咱們 PC 客戶端的離線包系統年久失修,在這個契機下,咱們啓動了使用 PWA 替換離線包的方案!
核心流程不變,基本和緩存靜態資源的流程是一致的
可是離線包系統是很是成熟的系統,要徹底替換掉它還須要考慮許多方面的問題。
離線包有個自動更新的機制,每隔一段時間就會去請求離線包管理系統是否有更新,有的話就把最新的離線包拉下來自動更新替換,這樣只須要1次跳轉就能展現最新的頁面。
SW 沒有自動更新的邏輯,它須要在頁面加載(一次跳轉)以後纔會去請求 sw.js,判斷有變化纔會進行更新,更新完了要等到下一次頁面跳轉(二次跳轉)才能展現最新的頁面。
這裏有兩個方案:
參考離線包的更新機制,也給 SW 實現一個自動更新的邏輯,借用 update 接口是能夠作到主動去執行 SW 更新的。可是很是遺憾,咱們的客戶端 webkit 內核版本過低,並不支持這個接口
在第一次跳轉以後更新 sw,而後檢測 sw 狀態,發現若是有更新,就用必定的策略來進行頁面的刷新
咱們使用第2個方案,部分代碼以下:
在檢測到 sw 更新以後,咱們能夠選擇強刷,或者提示用戶手動刷新頁面,具體實現頁面能夠經過監聽事件來處理
更多詳細的實現方案能夠參考這篇文章哈:How to Fix the Refresh Button When Using Service Workers: https://redfin.engineering/how-to-fix-the-refresh-button-when-using-service-workers-a8e27af6df68
通常離線包是打進 app 的安裝包一塊兒發佈的,在用戶下載安裝以後,離線包就已經存在於本地,所以第一次打開就能享受到離線包的緩存。
可是 sw 沒有這個能力,一樣咱們也有兩個方案:
在 app 安裝的時候,添加一步,經過建立 webview 加載頁面,頁面執行 SW 的初始化工做,並展現相應的進度提示,在安裝完成後須要把 webview 的 SW Cache 底層文件 copy 到相應的安裝位置。這個方案太複雜,衡量下來沒有采用。
在 app 啓動時,建立一個隱藏的 webview,加載空頁面去加載 SW。
咱們使用第2個方案,由於咱們的 app 啓動會先讓用戶登陸,以下圖所示:
注:這裏 app 不是移動端 app,是 pc 的客戶端 app
有時候咱們不想使用離線緩存能力,好比在咱們開發的時候
在離線包系統,一般會有一個開發者選項是【屏蔽離線包】
SW 也是須要這種能力的,這個方案就比較簡單了,在 sw.js 的邏輯裏有一個全局的開關,當開關關閉時,就不會走緩存邏輯
所以,咱們能夠在 dev 環境下把開關關閉便可達到屏蔽的做用
當咱們發佈了一個錯誤代碼的時候,咱們須要快速降級容錯的能力
在離線包系統裏面有個過時的功能,能夠把某個版本設置過時,也就是廢棄掉:
咱們利用以前提到的全局開關,經過一個管理接口來設置開關的起開和關閉,便可達到快速降級的目的:
整個流程大體是這樣:
發佈了錯誤代碼,而且用戶本地 sw 已經更新緩存了錯誤代碼
在管理端關閉使用緩存開關,讓用戶走線上
快速修復代碼併發布,到這裏頁面就已經恢復正常
在管理端開啓使用緩存開關,恢復 SW 功能
請求管理接口是輪詢的,這裏後續有計劃會改爲 push,這樣會更加及時,固然還要詳細評估方案以後才能落實。
咱們把上述功能集成到了一個 webpack 插件當中,在構建的時候就自動輸出 sw.js 並把相關內容注入到 html 文件中,該插件正準備開源哈~
將來對於 PWA 還能作些什麼?筆者覺得有如下 2 個方面
目前通用的能力已經基本挖掘完成,可是 SW 由於它獨特的特性,它能作的事情太多了,可是具體要不要這麼作也是因業務而異,並且這些內容可能會很複雜,因此我稱爲業務深耕。
SW 什麼特性?請看下面 2 張圖就能夠理解了
這種架構相信已經可以看出來了,沒錯,SW 有間件(層)的特性,那它能作的東西就太多了(雖然 SW 是用戶端本地中間層)
簡單舉幾個例子:
server 負載控制:當發現 server 端高負載時,SW 能夠丟棄請求,或者緩存請求,合併/延遲發送。
預請求:SW 能預緩存的資源是能夠構建出來的資源,可是咱們還有許多資源是不能在構建階段知道的,好比圖片,第三方資源等,SW 在返回資源請求(好比HTML、cgi 數據)以後,能夠掃描資源裏面的內容,若是發現包含了其餘資源的 url,那說明頁面頗有可能待會就會請求這些資源,這時 SW 能夠提早去請求這些資源;再好比翻頁的數據
緩存自動更新:經過與 server 創建聯繫,當數據有變化時,server 直接把最新的數據 push 到 SW 進行緩存的更新
回到最開始,PWA 是一項使人興奮的技術,可是瀏覽器兼容有限,所以期待並關注 PWA 技術的發展是頗有必要的!
固然,能推進就更好了!好比推進咱們的 X5 內核儘快支持新特性。
IMWeb 團隊隸屬騰訊公司,是國內最專業的前端團隊之一。
咱們專一前端領域多年,負責過 QQ 資料、QQ 註冊、QQ 羣等億級業務。目前聚焦於在線教育領域,精心打磨 騰訊課堂 及 企鵝輔導 兩大產品。