Web Workers
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); }) ) })