slideOptions:
transition: slide
---
# 建構 PWA - Service Worker
---
### 什麼是 Service Worker
----
- Service Worker 是一種 JS 的 Web Worker ,他是一隻獨立運行於瀏覽器頁面執行緒之外的一隻 JS 檔案,可以攔截網路請求,存取快取資源,並且能傳送訊息。
- 然後呢~Service Worker 大量的使用到 promise ,所以還沒搞懂的朋友們,你可能會看不懂這東西在搞什麼鬼QQ
- 因為 Service Worker 可以攔截你的網路請求,並且改變 response ,所以只能在 localhost 或是 https上使用。
---
### 生命週期
- Registration,要使用 Service Worker 之前必須先註冊一隻js檔案,這個動作其實是告訴瀏覽器,你這隻檔案的位置在哪
- Installation,當註冊了一個 Service Worker 之後,瀏覽器會在這個檔案還沒被安裝,或是跟原本的檔案有一點不一樣的時候,試圖去安裝
- Activation,當一個 Service Worker 安裝之後,就會進到這個階段,不過要是有任何的頁面還被前一個 Service Worker 控制的情況下,那新的 Service Worker 就會進入等待,直到沒有任何頁面被前一個控制。
---
### 動動手
----
#### 環境需求
----
- 瀏覽器要有支援,[看這裡](https://caniuse.com/#search=ServiceWorker)
- locahost 或是 https上
---
#### 建立專案
----
`mkdir demo-pwa && cd demo-pwa`
`touch index.html index.js sw.js`
`專案底下存兩張圖`
----
#### 寫code
----
index.js
```js=
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('./sw.js')
.then(reg => console.log('註冊啦~SW registered!'))
.catch(err => console.log('Error!', err));
}
```
----
sw.js
處理 install 事件
```js=
var fileToCache = [
"要放進快取的檔案",
"例如./index.js",
"例如圖片檔"
]
const cacheName = 'demo-pwa-static' //命名一個快取
self.addEventListener('install', event => {
console.log('installing…');
event.waitUntil(
// 打開這個名稱的cacheStroage,沒有的話就開一個空的cacheStroage
caches.open('demo-pwa-static').then(cache=>{
//fileToCache裡的路徑指向的檔案都加進快取
return cache.addAll(fileToCache)
})
)
});
```
----
處理 activate 事件
```js=
self.addEventListener('activate', event => {
console.log('now ready to handle fetches!');
event.waitUntil(
// 取得這個 application 下的所有 cacheStorage 名稱
caches.keys().then(function(cacheNames) {
console.log(cacheNames);
var promiseArr = cacheNames.map(function(item) {
if (item !== cacheName) {
// Delete that cached file
return caches.delete(item);
}
})
return Promise.all(promiseArr);
})
);
});
```
----
處理 fetch 事件
這個事件會攔截 request,並且回應 request
```js=
self.addEventListener('fetch', event => {
console.log('now fetch!');
console.log(event.request);
event.respondWith(
//當有重複的請求時,就直接拿cache裡的response當回應,沒有的話就送出請求,並且把回應存到cache裡
caches.match(event.request).then(function (response) {
return response || fetch(event.request).then(res =>
// 存 caches 之前,要先打開 caches.open(dataCacheName)
caches.open(dataCacheName).then(function(cache) {
// cache.put(key, value)
// 下一次 caches.match 會對應到 event.request
cache.put(event.request, res.clone());
return res;
})
);
})
);
});
```
---
### 參考
- [Introduction to Service Worker](https://developers.google.com/web/ilt/pwa/introduction-to-service-worker)
- [30 天 Progressive Web App 學習筆記 系列](https://ithelp.ithome.com.tw/users/20071512/ironman/1222)