在前端越來越重的這個時代,頁面加載速度成爲了一個重要的指標。對於這個問題,業界也有一些解決方案。
- 瀏覽器緩存、協議緩存、強緩存
- 懶加載(首屏)
- CDN 多域名突破下載併發限制。
其實在兩年前內部就對這塊內容做過調研了。appCache
方案?PWA
方案?但是最後都沒選擇。
之前看代碼,發現是 localstroage
存代碼,如果有就拿 localstroage
去用。省去了這一部分加載的時間。
上個同事離職了。當時的調研結果我也忘了。只能再開始新一輪的調研,我選擇的是 PWA
方案。(如果說是網速拖慢了加載速度,那麼我的網頁可以離線訪問不就速度起飛了?)
網上的資料很少。我希望我可以寫一篇幫助下一個想使用 PWA
方案的人。
Service Workers
Service worker
是一個註冊在指定源和路徑下的事件驅動worker
。
Service worker
運行在worker
上下文,因此它不能訪問DOM。不同於主線程,它運行在其他線程中,所以不會造成主線程阻塞。它設計爲完全異步,同步API(如XHR和localStorage)不能在service worker中使用。
Service workers
本質上充當Web應用程序(服務端)與瀏覽器(客戶端)之間的代理服務器。
可以提供有效有效的離線體驗,攔截網絡請求。還可以推送通知。
Service Workers 需要注意的地方
-
需要支持 HTTPS 訪問你的頁面。出於安全原因,
Service Workers
要求必須在HTTPS
下才能運行。(其實好多API
都需要HTTPS
的支持) - 資源路徑爲根目錄的絕對路徑。最大作用域 (
scope
),爲資源路徑。https://www.lilnong.top/static/js/sw-20190621.js
的最大作用路徑爲/static/js/
- 爲了便於本地開發,
localhost
也被瀏覽器認爲是安全源。 - 在已經支持
serivce workers
的瀏覽器的版本中,很多特性沒有默認開啓。如果你發現示例代碼在當前版本的瀏覽器中怎麼樣都無法正常運行,你可能需要開啓一下瀏覽器的相關配置:
Firefox Nightly: 訪問about:config
並設置dom.serviceWorkers.enabled
的值爲true
; 重啓瀏覽器;
Chrome Canary: 訪問chrome://flags
並開啓experimental-web-platform-features;
重啓瀏覽器 (注意:有些特性在Chrome
中沒有默認開放支持);
Opera: 訪問opera://flags
並開啓ServiceWorker
的支持; 重啓瀏覽器。
service worker 聲明週期
-
下載
- 首次訪問
service worker
控制的網站或頁面時,service worker
會立刻被下載。 - 至少每24小時它會被下載一次。
- 首次訪問
-
安裝
- 首次下載會嘗試安裝,
- 下載的文件是新的,嘗試進行安裝
-
激活
- 安裝成功後它會被激活
- 如果現有
service worker
已啓用,新版本會在後檯安裝,但不會被激活,這個時序稱爲worker in waiting
- 直到所有已加載的頁面不再使用舊的
service worker
纔會激活新的service worker
。新的service worker
會被激活(成爲active worker
)。
我們頁面引入sw.js
內容爲a
。當我們修改爲b
。
這時候a
和b
都是已經安裝完畢的,但是a
是當前正在用的。b
需要等沒有頁面在用a
,纔會進入激活狀態。
Cache
Cache
爲緩存的 Request
/Response
對象對提供存儲機制。
當前我們作爲 ServiceWorker
生命週期的一部分。儘管它被定義在 service worker
的標準中, 但是它不必一定要配合 service worker
使用。也暴露在 window
作用域下的。
- Cache.add(request)
request
是一個字符串類型的URL
。如cache.add('https://www.lilnong.top/static/css/normalize-8.0.0.css')
功能上等於調用fetch()
, 然後使用Cache.put()
將response
添加到cache
中。 - Cache.addAll(requests)
功能同上,只不過入參爲字符串數組 -
Cache.match(request, options)
返回一個Promise
對象,resolve
的結果是跟Cache
對象匹配已經緩存的請求。requres
同上,是要匹配的URL
options
如下-
ignoreSearch
: 設置是否忽略url
中的query
。該選項默認爲false
。 -
ignoreMethod
:true
匹配時就不會驗證Request
對象的http
方法 (通常只允許是GET
或HEAD
。) 該參數默認值爲 false。 -
ignoreVary
: 爲 true 時匹配不進行VARY
部分的匹配。例如,如果一個URL
匹配,此時無論Response
對象是否包含VARY
頭部,都會認爲是成功匹配。該參數默認爲 false。 -
cacheName
: 一個 DOMString ,代表一個具體的要被搜索的緩存。注意該選項被 Cache.match()方法忽略。
-
- Cache.matchAll(request, options)
同上,返回一個Promise 對象,resolve的結果是跟Cache對象匹配的所有請求組成的數組。 - Cache.put(request, response)
人爲的,爲一個URL
設置response
- Cache.delete(request, options)
搜索條目。如果找到,則刪除該Cache
條目,並且返回一個resolve
爲true
的Promise
對象;如果未找到,則返回一個resolve
爲false
的Promise
對象。 - Cache.keys(request, options)
返回一個Promise對象,resolve
的結果是Cache
對象key
值(request 對象)組成的數組。
ServiceWorker 的使用
-
serviceWorkerContainer.register()
來註冊 - 註冊成功的話,會開啓另一個線程來做這件事。與我們的網頁是互不相干的。
-
service worker
現在可以接收事件。 -
service worker
控制的頁面打開後會嘗試去安裝service worker
。 - 最先發送給
service worker
的事件是安裝事件(在這個事件裏可以開始進行填充 IndexDB和緩存站點資源),讓所有資源可離線訪問。 - 當
oninstall
事件的處理程序執行完畢後,可以認爲service worker
安裝完成了。 - 當
service worker
安裝完成後,會接收到一個激活事件onactivate
主要用途是清理先前版本的service worker
腳本中使用的資源。 -
Service Worker
現在可以控制頁面了,但僅是在register()
成功後的打開的頁面。
ServiceWorker 的註冊
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw-test/sw.js', { scope: '/sw-test/' }).then(function(reg) {
// registration worked
console.log('Registration succeeded. Scope is ' + reg.scope);
}).catch(function(error) {
// registration failed
console.log('Registration failed with ' + error);
});
}
微信公衆號
總結
測試路徑
https://www.lilnong.top/stati...
https
-
SW
通過fetch
來實現代理瀏覽器請求。 -
SW
註冊之後會嘗試安裝。但是激活需要等下次(沒有再用的資源了) -
SW
要注意他限制的域 -
importScripts('https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js');
是一個封裝包 -
vue-cli
也有一些webpack
支持的工具@vue/pwa
@vue/cli-plugin-pwa
資料
- Service_Worker_API --mdn
- Service Workers --mdn
- cache --mdn
-
AppCache --mdn
這個內容我覺得不用再關心了<html manifest="example.appcache">
- 前端每週清單半年盤點之 PWA 篇 ---王下邀月熊_Chevalier
- 傻傻分不清的Manifest
- PWA之 workbox 學習
- 初探PWA