在前一課咱們講過,經過在服務端設置http請求頭字段的方式,控制瀏覽器的靜態資源緩存規則 那麼,做爲前端開發,有沒有不須要後端配合的緩存方式呢? 下面,咱們就一塊兒來了解一下,在客戶端代碼控制web離線緩存的sevice worker。javascript
Service Worker 是 Chrome 團隊提出和力推的一個 WEB API,用於給 web 應用提供高級的可持續的後臺處理能力。 該 WEB API 標準起草於 2013 年,於 2014 年歸入 W3C WEB 標準草案,當前還在草案階段。css
Service workers 本質上充當Web應用程序與瀏覽器之間的代理服務器,也能夠在網絡可用時做爲瀏覽器和網絡間的代理。 它們可以建立有效的離線體驗,攔截網絡請求並基於網絡是否可用以及更新的資源是否駐留在服務器上來採起適當的動做。 他們還容許訪問推送通知和後臺同步API。前端
當瀏覽器發送請求時,首先到達sw腳本中,若是沒有命中,再轉發給http請求。java
sevice worker瀏覽器支持狀況 web
註冊 -> 安裝 -> 激活 -> 廢棄chrome
也能夠在開發者工具中查看瀏覽器中sevice worker的狀況 後端
f ('serviceWorker' in navigator) {
navigator.serviceWorker
.register('sw.js', {scope: '/'})
.then(registration => {
console.log('ServiceWorker 註冊成功!做用域爲: ', registration.scope)
})
.catch(err => {
console.log('ServiceWorker 註冊失敗: ', err)
});
}
複製代碼
代碼解析:promise
// 安裝階段跳過等待,直接進入 active
self.addEventListener('install', function(event) {
event.waitUntil(self.skipWaiting());
});
複製代碼
在下面的示例中,咱們實現對舊版本的緩存資源清理瀏覽器
this.addEventListener('activate', event => {
const cacheWhitelist = ['lzwme_cache_v1.6.0'];
event.waitUntil(
// 遍歷當前的緩存,刪除 指定版本號 以外的全部緩存
caches.keys().then(keyList => {
return Promise.all(keyList.map(key => {
if (cacheWhitelist.indexOf(key) === -1) {
return caches.delete(key);
}
}));
})
);
});
複製代碼
傳給 waitUntil() 的 Promise 會阻塞其餘的事件,直到它完成。這能夠確保清理操做會在第一次 fetch 事件以前完成緩存
參考下面的示例:
self.addEventListener('fetch', function(event) {
// console.log('Handling fetch event for', event.request.url);
event.respondWith(
// Opens Cache objects that start with 'font'.
caches.open(CURRENT_CACHES['carry']).then(function(cache) {
return cache.match(event.request).then(function(response) {
// 若是命中了緩存,直接返回緩存中的數據
if (response) {
console.log(' Found response in cache:', response);
return response;
}
// 請求是stream,只能使用一次
var fetchRequest = event.request.clone();
return fetch(fetchRequest)
.then(function(response) {
//請求不成功,則不存入緩存
if(!response || response.status !== 200) {
return response;
}
// 若是沒有命中緩存,將請求和響應緩存到cache中
// 響應也是stream,只能使用一次,一次用於緩存,一次用於瀏覽器響應
var responseToCache = response.clone();
caches.open(CURRENT_CACHES['carry'])
.then(function(cache) {
// 抓取請求及其響應,並將其添加到給定的cache
cache.put(event.request, responseToCache);
});
return response;
});
}).catch(function(error) {
// Handles exceptions that arise from match() or fetch().
console.error(' Error in fetch handler:', error);
throw error;
});
})
);
});
複製代碼
如下完整代碼
var CACHE_VERSION = 2;
// Shorthand identifier mapped to specific versioned cache.
var CURRENT_CACHES = {
carry: 'version' + CACHE_VERSION
};
const cacheList = [
'css',
'js'
]
// 安裝階段跳過等待,直接進入 active
self.addEventListener('install', function(event) {
event.waitUntil(self.skipWaiting());
});
self.addEventListener('activate', function(event) {
var expectedCacheNames = Object.keys(CURRENT_CACHES).map(function(key) {
return CURRENT_CACHES[key];
});
// Active worker won't be treated as activated until promise resolves successfully.
event.waitUntil(
caches.keys().then(function(cacheNames) {
return Promise.all(
// 更新客戶端
clients.claim(),
// 清理舊版本
cacheNames.map(function(cacheName) {
if (expectedCacheNames.indexOf(cacheName) == -1) {
console.log('Deleting out of date cache:', cacheName);
return caches.delete(cacheName);
}
})
);
})
);
});
self.addEventListener('fetch', function(event) {
console.log('Handling fetch event for', event.request.url);
let cached = cacheList.find(c => {return event.request.url.indexOf(c) !== -1 });
event.respondWith(
if(cached){
// 打開指定版本的緩存列表
// 每一個cache對象和請求的request url 匹配
caches.open(CURRENT_CACHES['carry']).then(function(cache) {
return cache.match(event.request).then(function(response) {
// 若是命中了緩存,直接返回緩存中的數據
if (response) {
console.log(' Found response in cache:', response);
return response;
}
// 請求是stream,只能使用一次
var fetchRequest = event.request.clone();
return fetch(fetchRequest)
.then(function(response) {
if(!response || response.status !== 200) {
return response;
}
// 若是沒有命中緩存,將請求和響應緩存到cache中
// 響應也是stream,只能使用一次,一次用於緩存,一次用於瀏覽器響應
var responseToCache = response.clone();
caches.open(CURRENT_CACHES['carry'])
.then(function(cache) {
// 抓取請求及其響應,並將其添加到給定的cache
cache.put(event.request, responseToCache);
});
return response;
});
}).catch(function(error) {
// Handles exceptions that arise from match() or fetch().
console.error(' Error in fetch handler:', error);
throw error;
});
})
}else{
return fetch(fetchRequest)
.then(response => {
return response;
})
}
);
});
複製代碼
致使廢棄的緣由
sevice worker的做用,遠遠不止請求資源緩存這一條,基於 Service Worker API 的特性,結合 Fetch API、Cache API、Push API、postMessage API 和 Notification API,能夠在基於瀏覽器的 web 應用中實現 如離線緩存、消息推送、靜默更新等 native 應用常見的功能,以給 web 應用提供更好更豐富的使用體驗。