[譯] JS 中 service workers 的簡介

banner

Service workersProgressive Web Apps的核心部分,容許緩存資源和Web推送通知等,以建立良好的離線體驗。它們充當Web應用程序,瀏覽器和網絡之間的代理,容許開發人員攔截和緩存網絡請求,並基於網絡的可用性採起適當的操做。javascript

一個service worker在單獨的線程上運行,所以它是非阻塞的。這也意味着它沒法訪問主JavaScript線程中可用的DOM和其餘API,好比cookie,XHR,Web存儲API(本地存儲和會話存儲)等。因爲它們被設計爲徹底異步,所以它們重度依賴promise來等待網絡請求的響應。css

出於安全考慮,service workers僅使用HTTPS運行,且不能在隱私瀏覽模式下使用。可是,在發出本地請求的時候,你不須要安全鏈接(這足以進行測試)。java

瀏覽器支持

Service Workers是一種相對較新的API,僅受現代瀏覽器的支持。所以,咱們首先須要檢查瀏覽器是否支持該API:git

if('serviceWorker' in navigator) {
    // Supported 😍
} else {
    // Not supported 😥
}
複製代碼

Service Worker 註冊

在咱們開始緩存資源或攔截網絡請求以前,咱們必須在瀏覽器中安裝service worker。因爲service worker本質上是一個JavaScript文件,所以能夠經過指定文件的路徑來註冊它。該文件必須能夠經過網絡訪問,而且只應包含service worker代碼。github

你應該等待頁面加載完成,而後將service worker文件路徑傳給navigator.serviceWorker.register()方法:json

window.addEventListener('load', () => {
    if ('serviceWorker' in navigator) {
        // register service worker
        navigator.serviceWorker.register('/sw-worker.js').then(
            () => {
                console.log('SW registration succesful 😍');
            },
            err => {
                console.error('SW registration failed 😠', err)
            });
    } else {
        // Not supported 😥
    }
});
複製代碼

每次頁面加載時均可以運行上面的代碼,沒有任何問題;瀏覽器將決定是否已經安裝service worker並相應地處理它。api

Service Worker 生命週期

註冊生命週期包括三個步驟:promise

  1. 下載
  2. 安裝
  3. 激活

當用戶首次訪問您的網站時,會當即下載service worker文件並嘗試安裝。若是安裝成功,則激活service worker。在用戶訪問另外一個頁面後刷新當前頁面以前,service worker文件中的任何功能都不可用。瀏覽器

瀏覽器事件

一旦service worker被安裝並激活了,它就能夠開始攔截網絡請求和緩存資源。這能夠經過監聽service worker文件中瀏覽器發出的事件來完成。瀏覽器發出如下事件:緩存

  • install 當安裝service worker程序時將發出install
  • activate 成功註冊和安裝service worker程序後將發送active。在安裝新版本以前,此事件可用於刪除過時的緩存資源。
  • fetch 只要網頁請求網絡資源,就會發出fetch。資源能夠是任何東西:新的HTML文檔,圖像,JSON API,樣式表或者JavaScript文件,以及遠程位置上可用的任何內容。
  • push 當收到新的推送通知時,push由Push API發送。你可使用此事件向用戶顯示通知
  • sync 當瀏覽器在鏈接丟失後檢測到網絡可用性時,將掉喲個sync

提供緩存資源

咱們能夠在安裝service worker時監聽install事件,以緩存當咱們離開網絡時須要爲網頁提供服務的特定資源:

const CACHE_NAME = 'site-name-cache';

self.addEventListener('install', event => {
    event.waitUntil(
        caches
            .open(CACHE_NAME)
            .then(cache =>
                cache.addAll([
                    'favicon.ico',
                    'projects.json',
                    'style.css',
                    'index.js',
                    'https://fonts.googleapis.com/css?family=Open+Sans:400,700'
                ])
            )
    );
});
複製代碼

上面的例子中,代碼使用Cache API將資源存儲在名爲site-name-cache的緩存中。

self關鍵字是一個只讀的全局屬性,service workers使用它來訪問本身。

如今讓咱們監聽一個fetch事件來檢查所請求的資源是否已經存儲在緩存中,若是找到則將其返回:

// ...
self.addEventListener('fetch', event => {
    event.respondWith(
        caches.match(event.request).then(response => {
            if (response) {
                //found cached resource
                return response;
            }
            return fetch(event.request);
        })
    );
});
複製代碼

咱們查找請求屬性標識的資源緩存條目,若是沒有找到,咱們會發送獲取請求。若是你也想緩存新的請求,能夠經過處理獲取請求的響應而後將其添加到緩存來完成,以下所示:

// ...
self.addEventListener('fetch', event => {
    event.respondWith(
        caches.match(event.request).then(response => {
            if (response) {
                //found cached resource
                return response;
            }

            // get resource and add it to cache
            return fetch(event.request)
                .then(response => {
                    // check if the response is valid
                    if (!response.ok) {
                        return response;
                    }

                    // clone the response
                    const newResponse = response.clone();

                    // add it to cache
                    caches.open(CACHE_NAME)
                        .then(cache =>
                            cache.put(event.request, newResponse)
                        );

                    // return response
                    return response;
                });
        })
    );
});
複製代碼

Service Worker 更新

安裝service worker程序後,它將繼續運行,直到用戶將其刪除或者更新爲止。要更新service worker,你須要作的就是在服務器上上傳新版本的service worker文件。當用戶訪問你的站點時,瀏覽器將自動檢測文件更改(即便只有一個字節更改就足夠了),並安裝新版本。

就像第一次安裝同樣,只有當用戶導航到另外一個頁面或刷新當前頁面時,新的service worker的功能才能使用。

咱們能夠作的事情就是監聽activate事件,並刪除舊的緩存資源。如下代碼經過遍歷全部緩存並刪除與緩存名稱匹配的緩存來完成此操做:

// ...
self.addEventListener('activate', event => {
    event.waitUntil(
        caches.keys().then(keys => {
            return Promise.all(
                keys.map(cache => {
                    if (cache === CACHE_NAME) {
                        return caches.delete(cache);
                    }
                })
            );
        })
    );
});
複製代碼

以上就是service workers的簡介了。若是你想了解更多,移步SerciceWorker Cookbook -- 這裏有一系列現代網站中使用service worker的實用例子。

參考和後話

更多的內容,請戳個人博客進行了解,能留個star就更好了💨

相關文章
相關標籤/搜索