Service Worker

 

1. Service Worker的身份

Service的意思是服務,Worker的意思是工人,那麼Service Worker的意思就是服務員。這個員工是2014年6月HTML5新招的實習生,目前在試用中。在此之前,已經有一位老員工,它叫Web Worker。那麼問題來了,Boss是誰?Boss就是瀏覽器。準確來說,每個頁面的javascript運行主線程都是一個Boss。

這裏先談一下大的背景。Boss很厲害,在頁面上指點江山,呼風喚雨。但他有個侷限:同一時刻只做一件事(單線程)。當一些很耗時的雜事讓Boss去處理時,在處理的過程中他就無暇顧及其它重要的事了。在用戶看來,頁面沒人管了,Boss不幹事了!這時Boss就很鬱悶。爲了保證Boss能處理更重要的事情,董事會(W3C)終於招聘了一個新員工:Web worker。這下,Boss終於可以從耗時的雜事中解放出來了,他只需要把Web worker叫過來說:“這些事情拿去做,沒做完不要來找我”。Web worker領到任務後默默地到自己的工位(線程)去幹活,完成之後給Boss發了個郵件(postMessage)。Boss收到郵件(onmessage)後欣慰地點了點頭。

扯了半天好像還沒談到新員工啊。。。不急,下面就講到了。

Boss下班了(頁面關閉),Web worker也收拾東西回家了。這樣執行了很久,直至2014年6月,董事會發現一個問題:“居然沒有人在老闆下班後加班?”。於是,又招了一個專職加班的:Service Worker。它被賦予的績效目標如下:

  1. 入職(install)後永不下班,而能更新。
  2. 能處理Boss需要的資源(HTTPS請求),以便離線時也能讓BOSS取到數據(從cache中)。
  3. 能向客戶推送消息(push notifications)
  4. 不允許越權管理Boss的事(DOM ACCESS)

總地來說,Service worker是獨立於頁面的一個運行環境,它在頁面關閉後仍可以運行。同時,也能對它負責的頁面的網絡請求進行截取和返回請求(類似於Fiddler)。

2. 使用條件

  • 請求協議條件 HTTPS。 畢竟給Service Worker的權利較大,可以直接截取和返回用戶的請求,所以了於安全考慮,目前只能在HTTPS環境下才能使用Service Worker。
  • 瀏覽器支持
     目前支持的瀏覽器不多,而且支持的瀏覽器也是在試驗階段。

    3. 一個栗子

    下面的例子將展示通過Service Worker來實現一個離線頁面,在第一次訪問後,後續即使沒有網絡連接,也能從緩存中獲取頁面必要的資源。例子源自github上一個demo
  • 頁面文件代碼:
<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Service Worker offline demo</title>
    <style>
        body {
            background-image: url("./images/background.jpeg");/*背景圖片*/
        }
    </style>
</head>
<body>

<div>Learn Web Design &amp; Development with SitePoint tutorials, 
courses and books - HTML5, CSS3, JavaScript, PHP, mobile app development, Responsive Web Design</div>
<script>
    if (navigator.serviceWorker) {
        // 註冊Service Worker scope表示作用的頁面的path
        // register函數返回Promise
        navigator.serviceWorker.register('./service-worker.js', {scope: './'}) 
            .then(function (registration) {
                console.log(registration);
            })
            .catch(function (e) {
                console.error(e);
            })
    } else {
        console.log('Service Worker is not supported in this browser.')
    }
</script>
</body>
</html>
  • Service Worker文件:service-worker.js
importScripts('js/cache-polyfill.js'); // cache 擴展

var CACHE_VERSION = 'app-v1'; // 緩存文件的版本
var CACHE_FILES = [ // 需要緩存的頁面文件
    '/',
    'images/background.jpeg',
    'js/app.js',
    'css/styles.css'
];


self.addEventListener('install', function (event) { // 監聽worker的install事件
    event.waitUntil( // 延遲install事件直到緩存初始化完成
        caches.open(CACHE_VERSION)
            .then(function (cache) {
                console.log('Opened cache');
                return cache.addAll(CACHE_FILES);
            })
    );
});

self.addEventListener('activate', function (event) { // 監聽worker的activate事件
    event.waitUntil( // 延遲activate事件直到
        caches.keys().then(function(keys){
            return Promise.all(keys.map(function(key, i){ // 清除舊版本緩存
                if(key !== CACHE_VERSION){
                    return caches.delete(keys[i]);
                }
            }))
        })
    )
});

self.addEventListener('fetch', function (event) { // 截取頁面的資源請求
    event.respondWith( // 返回頁面的資源請求
        caches.match(event.request).then(function(res){ // 判斷緩存是否命中
            if(res){  // 返回緩存中的資源
                return res;
            }
            requestBackend(event); // 執行請求備份操作
        })
    )
});

function requestBackend(event){  // 請求備份操作
    var url = event.request.clone();
    return fetch(url).then(function(res){ // 請求線上資源
        //if not a valid response send the error
        if(!res || res.status !== 200 || res.type !== 'basic'){
            return res;
        }

        var response = res.clone();

        caches.open(CACHE_VERSION).then(function(cache){ // 緩存從線上獲取的資源
            cache.put(event.request, response);
        });

        return res;
    })
}

 

  • Service Worker生命週期

    Service Worder在安裝(install)和激活(activate)後,會進入正常工作狀態。當它負責的頁面在瀏覽器中被打開,它就會對頁面的請求進行處理。在其它情況下(除了特殊情況:service worker會定時更新),Service worker處理暫停狀態,不會佔用內存和CPU資源。

  • 例子運行效果



    上圖爲在第一次打開頁面後,關閉網絡,再次打開的頁面請求。頁面在離線情況下仍然能打開,並且能獲取到相應的樣式和腳本資源。從圖中可以看出,資源的獲取途徑是“from ServiceWorker”,說明確實是serviceWorker在起作用了。

4. 開啓chrome隱藏技能

chrome上有三個與service Worker相關的調試和查看工具

  • 1 看正在運行的 serivce worker:chrome://inspect/#service-workers
  • 2 ervice Worker調試(查看console.log輸出,也可註銷worker)
  •  
  • 3 藏的Resources查看選項,開啓步驟如下:

    1 進入 chrome://flags 開啓 ‘Enable DevTools Experiments’.
    2 打開DevTools, 進入 Setting > Experiments , 連續按shift鍵6下
    3 在DevTools的Resources頁面裏就能看到剛被開啓的隱藏功能:

5. 總結

Service Worker是繼web Worker後又一個新的線程,這個線程比web worker獨立得更徹底,可以在頁面沒有打開的時候就運行。作爲一個頁面與服務器之間中間層,Service Worker可以捕獲它所負責的頁面的請求,並返回相應資源,這使離線web應用成爲了可能。這也是Service Worker被提出的一個重要目的。雖然現在支持的瀏覽器和平臺還不多,而且還在試驗階段,但已被W3C制定規範。在將來,當Service Worker更成熟和普及時,將會爲web app打開新的大門。

 

轉自:https://www.imweb.io/topic/56592b8a823633e31839fc01

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章