Web Workers处理线程
概念:在web应用程序中实现后台处理前端逻辑的技术
为什么会有Web Workers处理线程
- 在HTML之前的web程序,所有的处理都是在单线程中执行的;
- 如果花费时间长,程序界面会一直处于长时间没有响应的状态;
- 如果长到一定程度,浏览器会弹出一个提示脚本运行时间过长的提示框;
- 用户不得不中断正在执行的处理;
创建Web Workers的方式
index.html:
<script>
// 注意:后台线程中不可以使用window/document对象
const worker = new Worker('sumCalculate.js') //传入需要再后台执行脚本的url地址
// 接受消息
worker.onmessage = function (e) {
// 处理接受的消息
alert('合计值:' + e.data)
}
// 发送消息
function calcute() {
const num = parseInt(document.getElementById('num').value, 10)
worker.postMessage(num)
}
</script>
输入数值:<input type='text' id='num'>
<button onclick='calcute'>计算</button>
sumCalculate.js(后台计算进程):
onmessage = function(e) {
const num = e.data;
let result = 0
for(let i=0;i<= num; i++) {
result += i
}
postMessage(result)
}
线程嵌套
线程可以嵌套子线程,因此比较大的线程可以分成几个子线程,独立完成工作
-
主线程代码(index.html)
<script> // 创建线程 const worker = new Worker('test1.js') // 发送信息 worker.postMessage('') // 接受消息 worker.onmessage = function (e) { if (e.data !== '') { // 业务逻辑 } } </script>
-
子线程1代码(test1.js)
onmessage = function (e) { const intArray = new Array(100) for(let i=0; i < 100; i++) { intArray[i] = parseInt(Math.random() * 100) } let worker; // 创建子进程2 worker = new Worker('test2.js') // 向子进程2发送数据 worker.postMessage(JOSN.stringify(intArray)) worker.onmessage = function (e) { postMessage(e.data) } }
-
子线程2代码(test2.js)
onmessage = function (e) { const intArray = JSON.parse(e.data) let returnStr = '' for(let i=0; i < 100; i++) { if (parseInt(intArray[i]) % 3 === 0) { if (returnStr != '') { returnStr += ';' } returnStr += intArray[i] } } // 发送消息 worker.postMessage(returnStr) // 关闭进程 close() }
线程中可用的变量、函数、类
web workers是属于后台执行前端的js代码,只能使用js中的部分对象和方法
- self: 本线程范围内的作用域
- postMessage: 用于向线程的源窗口发送信息
- onmessage: 获取线程传回来的信息
- importScript(urls): 导入其它javascript文件,例如importScript(‘test1.js’,‘test2.js’)
- navigator: 和window.navigator一样,具有appName,platform,userAgent,appVersion
- sessionStorage/localStorage: 可以使用web Storage
- XMLHttpRequest:线程中处理Ajax请求
- Web Worker: 创建嵌套线程
- setTimeout/setInterval:线程中实现定时处理
- close: 结束线程
- eval(),isNaN(),escape()等所有js核心函数
- object:创建和使用本地对象
- WebSockets: 使用WebSockets向服务器发送和接受消息
- FileSystem: 在线程中通过同步的FileSystem API实现受沙箱保护的文件系统的文件和目录的创建、更新、删除操作
SharedWorker共享线程
多个页面可以共用一个后台线程,后台线程可以作为一个提供服务的场所
创建线程
//url为后台执行的脚本文件地址,name为指定线程的名称,可选参数
const worker = new ShareWorker(url,[name])
// 单线程/多线程
// worker1和worker2共享一个后天线程
const worker1 = new ShareWorker('test.js')
const worker2 = new ShareWorker('test.js')
// worker1和worker2为两个后台线程
const worker1 = new ShareWorker('test1.js')
const worker2 = new ShareWorker('test2.js')
// worker1和worker2共享一个后天线程
const worker1 = new ShareWorker('test.js', 'nama1')
const worker2 = new ShareWorker('test.js', 'nama1')
// worker1和worker2为两个后台线程
const worker1 = new ShareWorker('test.js', 'nama1')
const worker2 = new ShareWorker('test.js', 'nama2')
前台页面和后台线程通信
// 创建共享进程
const worker1 = new ShareWorker('test.js')
// MessagePort对象
const port = worker1.port
// 向另一个页面发送消息
port.postMessage(message)
port.onmessage = function (e) {
// 处理收到的信息
}
// 激活端口,开始监听端口是否有接受到信息
port.start()
// 关闭并停用端口
port.close()
// 子进程后台connect对象
onconnect = function (e) {
// 处理接受的消息
// 取得页面上的ShareWorker对象的端口
const port = e.ports[0]
port.onmessage = function (e) {
// 向页面返回接受的信息
port.postMessage(e.data)
}
}
SharedWorker的使用示例
-
单个页面中使用SharedWorker
主页面代码:
// 创建共享进程 const worker1 = new ShareWorker('test.js') // MessagePort对象 const port = worker1.port // 向另一个页面发送消息 port.start() port.postMessage(message) port.onmessage = function (e) { // 处理收到的信息 }
进程test.js代码:
// 子进程后台connect对象 onconnect = function (e) { // 处理接受的消息 // 取得页面上的ShareWorker对象的端口 const port = e.ports[0] port.onmessage = function (e) { // 向页面返回接受的信息 port.postMessage('ninhao') } }
-
多个页面中使用SharedWorker
第一个页面代码:
// 创建共享进程 const worker1 = new ShareWorker('test1.js') // MessagePort对象 const port = worker1.port port.start() // 向另一个页面发送消息 port.postMessage(1) port.onmessage = function (e) { // 处理收到的信息 }
第二个页面代码:
// 创建共享进程 const worker1 = new ShareWorker('test1.js') // MessagePort对象 const port = worker1.port // 向另一个页面发送消息 port.start() port.postMessage(2) port.onmessage = function (e) { // 处理收到的信息 }
进程test1.js代码:
// 子进程后台connect对象 onconnect = function (e) { // 处理接受的消息 // 取得页面上的ShareWorker对象的端口 const port = e.ports[0] port.onmessage = function (e) { // 向页面返回接受的信息 port.postMessage(e.data * e.data) } }