Web Workers

633 阅读1分钟

什么是 Web Worker?

我们一直强调JavaScript是单线程的,但是web worker的出现使得JavaScript可以在多线程上跑,只是web worker本身适合用于一些复杂的、耗费cpu的运算,不能操作window、document、parent对象,所以说本质上的JavaScript还是单线程的。

  web worker就是运行在后台的JavaScript,独立于其他脚本,不会影响页面的性能。您还可以做任意想做的事情,不会影响点击等操作。

Web Worker 有三种类型:

  • Dedicated Worker(专用 Worker):由主线程实例化且只能与它通信,不能访问别的环境。
  • Shared Worker(共享 Worker):所有 Shared Worker 实例共享一个全局环境,多个页面可以用 Shared Worker 互相通信,可以处理多个连接。
  • Service worker(服务 Worker):具有 Shared Worker 的特点、通过事件驱动,可以随时关闭再重启、不需要任何页面也能工作,只支持 https 和 localhost。多用于离线场景

平常使用最多,最常见的就是 Dedicated Worker,并且 Dedicated Worker 兼容性较好

为什么需要web worker?

对于耗时而不操作DOM的JavaScript,我们就可以使用web worker,增强性能。

web worker有什么要注意的地方? 

  • 不是所有的浏览器都支持,使用前要检查浏览器是否支持。 
  • web worker运行于外部文件中,所以他们无法访问下面的JavaScript对象。
  • 理解好 worker,worker在计算机领域通常被翻译为线程或者是进程。而这里的worker意义也是如此。 我们需要将之正确对待。

web worke基本用法

var worker = new Worker('work.js');
  <p>计数:<span id="result"></span></p>
  <button onclick="start()">web worker开始工作</button>
  <button onclick="stop()">web worker结束工作</button>
  
  <script>
    var w;
    function start() {
      if (typeof Worker != 'undefined') {
      
        w = new Worker('worker.js');  // 创建 Web Worker 对象
        
        // 向 web worker 添加一个 "onmessage" 事件监听器:
        w.onmessage = function (event) {
          document.getElementById('result').innerHTML = event.data;
        }
        
      } else {
        document.getElementById('result').innerHTML = '您的浏览器不支持web worker';
      }

    }

    function stop() {
      w.terminate();  // 终止 Web Worker
      w = undefined;
    }

SharedWorker使用

SharedWorker 是一种特殊的 WebWorker,可有支持多个浏览器上下文的通信功能,例如多个窗口、iframe。

但是与普通 Worker 不同的是:
1 同一个js url 只会创建一个 sharedWorker,其他页面再使用同样的url创建sharedWorker,会复用已创建的 worker,这个worker由那几个页面共享。
2 sharedWorker通过port来发送和接收消息

接下来,我们看一下具体是 worker 和页面之间是如何发送和接收消息的。

方法

  • start:开启连接
  • connect:连接
  • postMessage:发送数据
  • onmessage:接收数据
<body>
    <input type="text" id="input">
    <button id="submit">提交</button>
    <p id="news"></p>
</body>
<script>
    let work = new SharedWorker('work.js');
    let port = work.port;
    //开启
    port.start();
    //通知所有人
    port.postMessage({ type: "start" });
    //点击触发事件
    submit.onclick = function (e) {
        port.postMessage({
            type: "msg",
            value: input.value
        });
        input.value = "";
    }
    //接收数据
    port.onmessage = function (e) {
        console.log(e.data)
        if (Array.isArray(e.data)) {
            let html = "";
            e.data.forEach(msg => {
                html += `<p>${msg}</p>`;
            });
            news.innerHTML = html;
        } else {
            news.innerHTML = e.data;
        }
    }
</script>