HTTP響應頭的實現(xiàn)
如果一個網(wǎng)站中的某個文件是百年不變的坦康,那么肯定沒有必要打開網(wǎng)頁都重新獲取啊巍虫。我們可以設置HTTP返回頭的Cache-Control瞬逊。
max-age=31536000:過期時間(單位是秒)碱呼,最大不能超過一年,只要沒過期或者手動清除緩存就會使用緩存蔗牡。
no-cache:每次使用緩存之前颖系,向服務器對資源進行驗證。最終實現(xiàn)不使用緩存的過期資源的效果辩越。(不要理解為字面意思:不緩存)
no-store:不使用緩存
must-revalidate:如果設置了
max-age
嘁扼,在有效期內(nèi)會使用緩存,否則就需要進行驗證黔攒。所以可以結(jié)合使用Cache-Control: must-revalidate, max-age=60
偷拔。
那么服務端怎么進行驗證呢?服務器第一次返回的響應頭中有一個ETag
字段亏钩,該字段相當于一個標識,具體的生成邏輯由服務端決定欺旧。
然后客戶端之后的請求頭中會攜帶一個If-None-Match
字段姑丑,這個字段就是那個標識。服務器通過對比這個標識判斷資源是否發(fā)生了更新辞友。
Expires VS max-age
在響應頭中有時還有一個expires
字段栅哀,它和設置max-age
一樣都是設置有效期的。不過expires
字段直接指定過期時間称龙。而后者則是指定多長時間之后過期留拾。
expires: Mon, 24 Dec 2018 13:55:24 GMT
last-modified VS Etag
在響應頭中還有一個字段last-modified
,它也可以用來做驗證鲫尊。那么它與Etag
有什么區(qū)別呢痴柔?可以說Etag
應該是更為精準的,last-modified
最多精確到秒疫向,而Etag
則是只要發(fā)生變化咳蔚,標識就會改變豪嚎。
last-modified: Thu, 01 Jan 1970 00:00:00 GMT
Service Workers
1、Service Workers是什么谈火?
Service Workers
是瀏覽器在后臺獨立于網(wǎng)頁運行的腳本侈询,它可以支持離線體驗。有以下幾點注意事項:
它是一種JavaScript 工作線程糯耍,不能直接訪問DOM
服務工作線程是一種可編程網(wǎng)絡代理扔字,讓您能夠控制頁面所發(fā)送網(wǎng)絡請求的處理方式。
它在不用時會被中止温技,并在下次有需要時重啟
在開發(fā)過程中革为,可以通過 localhost 使用服務工作線程,但如果要在網(wǎng)站上部署服務工作線程荒揣,需要在服務器上設置 HTTPS篷角。
2、生命周期
首先需要在我們的網(wǎng)頁中注冊
Service Workers
系任。注冊會讓瀏覽器后臺執(zhí)行Service Workers的安裝步驟恳蹲。在Service Workers的獨立腳本中,設置在安裝過程中要緩存的文件俩滥,如果所有文件都緩存成功則安裝成功嘉蕾;如果有任何一個失敗都將失敗,Service Workers就安裝失敗霜旧。
安裝完成就該激活了错忱,在這里我們對舊緩存進行管理。
激活之后挂据,服務工作線程將會對其作用域內(nèi)的所有頁面實施控制
接下來以清,我們詳細了解一下各個步驟的代碼寫法:
3、代碼實現(xiàn)
在頁面中注冊Service Workers
崎逃,來啟動安裝掷倔。在register方法中告訴瀏覽器Service Workers
腳本的路徑,這里是在根目錄下个绍,所以Service Workers
接受該域下所有的fetch事件勒葱。
// 判斷瀏覽器對Service Workers的支持情況
if ('serviceWprker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker
.register('/sw.js')
.then(registration => {
if (registration.waiting) {
console.log('安裝完畢');
}
})
.catch(err => {
console.log(err);
});
});
}
接下來看一下Service Workers
中的安裝過程,這里會監(jiān)聽一個install事件巴柿,在事件回調(diào)中又可以分為三部:
var CACHE_NAME = 'my-cache';
var cacheList = ['/', '/src/main.js'];
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME).then(cache => {
return cache.addAll(cacheList);
})
);
});
打開緩存凛虽,這里需要傳入一個想要緩存的自定義名稱。
緩存文件广恢,可以是一個由想要緩存的文件路徑組成的數(shù)組
確認所有需要的資產(chǎn)是否緩存凯旋,event.waitUntil() 方法帶有 promise 參數(shù)并使用它來判斷安裝所花費的時間以及安裝是否成功。
在安裝完成之后,我們可能會想要一個對fetch事件的處理瓦阐,當監(jiān)聽到fetch請求時蜗侈,先匹配緩存中的內(nèi)容,如果有就返回緩存的內(nèi)容睡蟋,沒有則發(fā)起網(wǎng)絡請求踏幻。
self.addEventListener('fetch', event => {
event.respondWith(
caches
.match(event.request)
.then(response => response || fetch(event.request))
);
});
這里如果想要連續(xù)緩存新的請求,可以處理fetch請求的響應并將其添加到緩存中戳杀。
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(response => {
if (response) {
return response;
}
// 如果時新的請求就克隆一個請求
var fetchRequest = event.request.clone();
return fetch(fetchRequest).then(res => {
// 校驗響應该面,對第三方資產(chǎn)(type)的請求不會添加到緩存
if (!res || res.status !== 200 || res.type !== 'basic') {
return res;
}
// 該響應是Stream,所以主體只能用一次信卡,需要克隆響應隔缀,一個發(fā)送給瀏覽器,一個保留在緩存中
var responseToCache = res.clone();
caches.open(CACHE_NAME).then(cache => {
cache.put(event.request, responseToCache);
});
return res;
});
})
);
});
接著看傍菇,當某個時候猾瘸,Service Workers
需要更新了,應該有以下步驟:
在用戶打開頁面的時候瀏覽器會嘗試在后臺重新下載定義了
Service Workers
的腳本丢习。如果有變化了就認為是更新了牵触。這時新的
Service Workers
就會啟動將觸發(fā)install
事件,此時此刻舊的Service Workers
還在控制著頁面咐低,新的Service Workers
處于waitting狀態(tài)當前這個頁面關閉之后揽思,新的
Service Workers
就會占據(jù)控制權。新服務工作線程取得控制權后见擦,就會觸發(fā)其 activate 事件钉汗。
在 activate 回調(diào)中一般就是進行緩存管理,把舊的Service Workers
清除掉鲤屡。先定義一個新的緩存百名單损痰,然后遍歷Service Workers
所有的緩存,把不在白名單內(nèi)的刪除酒来。
self.addEventListener('activate', event => {
// 白名單
var cacheWhiteList = ['new-cache'];
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cacheName => {
if (cacheWhiteList.indexOf(cacheName) === -1) {
return caches.delete(cacheName);
}
})
);
})
);
});