WebWorker
- WebWorker为JavaScript创造了多线程并发的程序执行环境,可以把一些耗时操作放入worker线程异步执行.而后通知主线程绘制界面.
- javascript采用的是单线程模型,也就是说几乎所有操作只在主线程中执行.
案例:
- 创建一个耗时代码(斐波那契数列),感受阻塞主线程的现象
1 1 2 3 5 8 13 21 34 55 89 ......
function fb(n){
return n<3 ? 1 : fb(n-1)+fb(n-2)
}
使用WebWorker
1. 新建worker.js,把需要执行的耗时代码写在这里.
//work.js
// 把耗时代码写在这里
// 递归实现斐波那契数列
function fb(n) {
return n < 3 ? 1 : fb(n - 1) + fb(n - 2)
}
console.log(fb(44))
2. 在html里的主线程js代码中,创建worker对象加载work.js,即相当于创建子线程并且执行worker.js中的耗时代码.
<script>
// 为btn2绑定事件
btn2.addEventListener('click', () => {
// 创建并启动webworker,异步执行worker.js的代码
let worker = new Worker('./work.js')
})
</script>
注意: 千万注意new Worker()时要考虑cpu和内存,防止worker创建过多,理论上来讲一个页面中一般3-5个worker就够.
所以一般情况下,在页面加载时就创建webworker,但是仅仅创建,并不执行耗时代码.当点击按钮或触发某些事件时,才去通知webworker执行耗时代码.就需要了解主线程与worker线程之间如何通信.
主线程与webworker线程通信
页面UI只能由主线程更新
webworker子线程是不能更新UI的
axios.get('/category').then(res=>{
let d = document.getElementById('div')
d.innerHTML = res.data.text
})
//axios是异步发送请求,是在子线程进行的.
//但是res后的代码是在主线程执行的.
主线程向子线程发消息
在页面加载时就创建webworker,但是仅仅创建,并不执行耗时代码.当点击按钮是,才去通知webworker执行耗时代码.所以需要在主线程向子线程发消息.
主线程如何发?
let worker = new Worker('worker.js')
worker.postMessage('数据')
子线程如何收?
//work.js中
onmessage = (data) =>{
console.age(data)
}
//子线程接收到数据后需要执行完后续代码才会接收下一条数据.
子线程向主线程发消息
子线程如何发?
//worker.js中
this.postMessage('结果')
//this可以省略
主线程如何收?
let worker = new Worker('worker.js')
worker.onmessage = (data)=>{
//更新UI
}
//主线程接收消息也是创建监听,不能写在监听发送消息的事件内部,应写在最外层,避免多次创建监听.