Web Worker初体验

194 阅读2分钟

Web Worker已经出来挺久了吧,算不上很新的技术,但是一直没用过,今天简单使用一下。

Web Worker 是什么?

web worker到底是什么,简单明了的一句话其实就是在Javascript单线程执行的基础上,开启一个子线程,进行程序处理,而不影响主线程的执行,当子线程执行完毕之后再回到主线程上,在这个过程中并不影响主线程的执行过程。

Web Worker的限制

  • 不可以操作dom
  • 不可以访问window、document之类的浏览器全局变量、方法
  • 不可以访问全局变量或是全局函数。

怎么使用?

ps:有关直接使用web worker报错的,可以看我上一篇文章。

    //主线程
    let myWorker = new Worker('worker.js',{name:'first'})
    //worker构造函数接收两个参数,
    //第一个是路径,第二个是一个对象用来指定worker的名字。
    myWorker.postMessage('主线程发了一条数据') //给子线程发送数据
    myWorker.onmessage = function(event){  //监听子线程发的数据
        console.log('主线程',event)
    }
    myWorker.onerror = function(error) { //监听子线程的错误
            console.log(error)
     };
    myWorker.terminate() //关闭子线程
    
    //子线程
    //这里需要知道的就是 在 worker 中没有 window 实例,也没有全局的 this,
    //但是却有着 WorkerGlobalScope 也就是 self,当前 worker 自己。
    self.onmessage = function(event){
       console.log("子进程接收到了消息:",event)
    } //监听主进程的消息
    self.postMessage("子进程发送了一条消息") //子进程给主进程发消息
    self.close(); //子进程关闭自己

image.png

使用的时候其实很简单,就几行代码。

我们都知道alert会阻塞js代码执行,我们在主线程里使用alert,在子进程使用setInterval看看什么效果?

    //主进程
        let myWorker = new Worker('worker.js',{name:'first'})
        setTimeout(() => {
            alert('阻塞!!!')
        }, 3000);
    //子进程
    setInterval(() => {
        console.log('子进程')
    },1000);

image.png 很明显子进程并不会收到影响,这就是webworker的好处。

练习 监听两个input框输入的值,然后交给webworker计算。

    a <input type="text" id="first">
    <br>
    b <input type="text" id="second">
    <br>
    <button>点击关闭子进程</button>
//主进程
        let first = document.querySelector('#first')
        let second = document.querySelector("#second")
        let button = document.querySelector('button')
        let myWorker = new Worker('worker.js',{name:'first'})
        first.onchange = function(e){
            myWorker.postMessage([first.value,second.value])
        }
        second.onchange  = function(e){
            myWorker.postMessage([first.value,second.value])
        }
        myWorker.onmessage = function(event){
            console.log('主线程收到了,和是:',event.data)
        }
        myWorker.onerror = function(error) {
            console.log(error)
        };
        button.onclick = function(){
            myWorker.terminate()
        }
//子进程
self.onmessage = function(event){
    let num1 = event.data[0]
    let num2 = event.data[1]
    self.postMessage(~~num1 + ~~num2)
    // ~~ 是为了把字符串转为数字
}

看效果 :

image.png

image.png

总结

Worker本质是一个线程,在UI主线程之外并发执行的线程;用于执行耗时的JS任务;缺陷:不能操作BOM和DOM,只能和UI主线程发消息。用完记得关闭worker。