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。它被賦予的績效目標如下:
- 入職(install)後永不下班,而能更新。
- 能處理Boss需要的資源(HTTPS請求),以便離線時也能讓BOSS取到數據(從cache中)。
- 能向客戶推送消息(push notifications)
- 不允許越權管理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 & 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打開新的大門。