Web Worker的简单使用

112 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第五天,点击查看活动详情

题引:

当我们在开发系统的时候,有时候需要利用多线程的方法来处理一些耗时的任务且不堵塞主线程的运行。对于JavaScript这种单线程的语言来说是无法实现的,但是我们可以借用浏览器的web worker来提供线程支持。

正文:

概述:

web Worker为Web内容在后台线程中运行脚本提供了一种简单的方法。线程可以执行任务而不干扰用户界面。

作用:

它的作用就是把JS创建多线程运行环境,允许主线程利用浏览器创建worker线程,分配任务在后者。主线程运行的同时worker线程也在运行,互不干扰,在worker线程运行完之后把结果返回给主线程。

这样做的好处就是主线程可以把计算机密集型或者高消耗的任务交给worker线程,减少主线程的堵塞。

eg:这不意味着JavaScript语言本身就有多线程能力,永远记住JavaScript是单线程语言。web Worker浏览器作为宿主环境为JavaScript提供了多线程运行的环境。

API介绍:

主线程和worker线程有不同的api

主线程:

在主线程中,worker是Worker的实例,以下是常用API

  • worker.postMessage: 主线程往worker线程发消息,消息可以是任意类型数据,包括二进制数据
  • worker.onmessage: 指定worker线程发消息时的回调,也可以通过worker.addEventListener('message',cb)的方式
  • worker.onerror: 指定worker线程发生错误时的回调,也可以 worker.addEventListener('error',cb)
  • worker.terminate: 主线程关闭worker线程

Worker线程:

Worker线程有自己的全局对象,不是主线程的window,而是一个专门为 Worker 定制的全局对象。Worker线程中全局对象为 self,代表子线程自身,这时 this指向self,且定义在window上面的对象和方法self不是全部都可以使用。
以下是常用API

  • self.postMessage: worker线程往主线程发消息,消息可以是任意类型数据,包括二进制数据
  • self.onmessage: 指定主线程发worker线程消息时的回调,也可以self.addEventListener('message',cb)
  • self.onerror: 指定worker线程发生错误时的回调,也可以 self.addEventListener('error',cb)
  • self.close: worker线程关闭自己

其实说到底就是接收、发送、监听、关闭等方法啦。

使用demo:

这里引用别人的实例来展示

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div>
      Worker 输出内容:<span id="app"></span>
      <input type="text" title="" id="msg" />
      <button onclick="sendMessage()">发送</button>
      <button onclick="stopWorker()">stop!</button>
    </div>
    <script type="text/javascript">
        if(typeof Worker === 'undefined'){
            document.writeln(" Sorry! No Web Worker support.. ");   
        }else{
            const worker = new Worker('./test.js')
            // 接收信息监听
            worker.onmessage = (ev)=>{
                document.querySelector('#app').innerHTML = `worker线程的信息:${ev.data}`;
            }
            // 错误监听
            worker.onerror = (err)=>{
                // 停止终端
                worker.terminate();
                // 发生错误的文件名、行号、错误内容
                console.log(err.filename,err.lineno,err.message);
            }
            function sendMessage(){
                const msg = document.querySelector('#msg');
                worker.postMessage(msg.value);
            }
            function stopWorker(){
                worker.terminate();
            }
        }
    </script>
  </body>
</html>
let i = 1;

function simpleCount() {
  i++;
  self.postMessage(i);
  setTimeout(simpleCount, 1000);
}
simpleCount();

self.onmessage = (ev) => {
  self.postMessage(`主线程发来信息:${ev.data}`);
};

在日常的开发中,如果只需要分发高消耗任务到worker线程上,是比较简单实现的,但如果是实现特殊的需求,就需要自己多钻研了。

使用场景:

  1. 数据预渲染:

    为了提高数据加载速度,可以提前使用Web Worker线程获取数据,因为Web Worker可以使用XMLHttpRequest

  2. 数据复杂处理:

    数据过于庞大的检索、排序、过滤、分析会非常耗费时间,这时可以使用Web Worker来进行,不占用主线程。

当然还有很多的使用场景,我只举例了我用到的场景。

结尾:

今天的每日一篇就到这了,感谢阅读。