Web Worker SharedWorker Service Worker ...
Web Worker
- 模擬多線程,允許腳本在後臺運行,所以不會阻止其他腳本的運行;是保持UI響應的同時也執行處理器密集型功能的解決方案;不能直接與dom交互,不能使用window、document、parent等對象;通信用postMessage發消息和onmessage監聽接受消息;
- Web Workers利用線程消息傳遞來實現並行性;
-
// 主程式 let worker = new Worker('./worker.js'); worker.postMessage(123); worker.addEventListener('message', e => { console.log(`收到來自worker線程的信息: ${e.data}`) }) document.querySelector('button').addEventListener('click', ()=>{ worker.terminate(); }) for(let i=0;i<10;i++){ setTimeout(()=>{ console.log(i) }, 1000*i) } // worker線程 self.addEventListener('message', e => { console.log(`收到來自主程式的信息: ${e.data}`); postMessage(666) }) var i=0; function timedCount(){ i=i+1; postMessage(i); setTimeout("timedCount()",1000); } timedCount(); // 關閉worker線程 self.close();
SharedWorker
- 由獨立的進程管理,WebWorker只是屬於render進程下的一個線程
Service Worker
- 本質上充當web應用程式與瀏覽器間的代理伺服器,可攔截網路請求並基於網路是否可用以及更新的資源是否駐留在伺服器上來採取適當的動作,也用於離線情況下後臺同步或推送通知的處理方案;同時運行在worker上下文也不能直接與dom交互,通信和webworker一樣;
- 相對於應用的主js線程,它運行在其他線程中,所以不會造成阻塞。它設計為完全非同步,同步API(如xhr和localStorage)不能在service worker中使用;只能在https下使用;
- 會基於promise和fetch;
- 生命周期:
parsed(註冊完成,腳本解析成功,尚未安裝)
installing(對應sw腳本install事件執行)
installed(頁面被舊的sw腳本控制,當前腳本尚未激活)
activating(對應sw腳本activate事件執行)
activated(激活成功)
redundant(安裝失敗或激活失敗,或被新的sw替代) - 事件:
install(抓取資源進行緩存)
activate(遍歷緩存,清除過期資源)
fetch(攔截請求,查詢緩存或網路,返回請求的資源) -
// 註冊 if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/sw-test/sw.js', { scope: '/sw-test/' }).then(function(reg) { console.log('Registration succeeded. Scope is ' + reg.scope); }).catch(function(error) { console.log('Registration failed with ' + error); }); } // 下載安裝 self.addEventListener('install', e => { console.log('[sw] installed'); e.waitUntil( // caches.open() 打開緩存並提供一個緩存名稱 caches.open(cacheName).then(cache => { console.log('cache app shell'); // 從伺服器獲取文件,並將響應添加至緩存,具有原子性(一個緩存失敗都失敗) return cache.addAll(filesToCache); }) ) }) // 激活 // activate事件會在服務工作線程啟動時觸發 self.addEventListener('activate', e => { console.log('[sw] activated'); e.waitUntil( caches.keys().then(keyList => { return Promise.all(keyList.map(key => { if(key !== cacheName){ console.log(`[sw] removing old cache: ${key}`); return caches.delete(key); } })) }) ) return self.clients.cliam(); }) // 從緩存提供app shell self.addEventListener('fetch', e => { console.log(`[sw] fetch: ${e.request.url}`); e.respondWith( // caches.match() 會由內而外對觸發抓取事件的網路請求進行評估,並檢查以確認它是否位於緩存內 caches.match(e.request).then(response => { return response || fetch(e.request); }) ) })