web workers简介(一)基础使用

栏目: 编程工具 · 发布时间: 6年前

内容简介:大家好,今天在这里简单介绍一下web workers的基本使用。web workers可以使得一些涉及复杂计算的逻辑在独立的线程运行,从而不会影响页面的性能,例如渲染、交互响应等。web workers中可以使用大多数标准的JS特性,例如XMLHttpRequest等;当然web workers也有不少局限行,例如不能操作DOM、作用域是独立的等等。

大家好,今天在这里简单介绍一下web workers的基本使用。

web workers

web workers可以使得一些涉及复杂计算的逻辑在独立的线程运行,从而不会影响页面的性能,例如渲染、交互响应等。

web workers中可以使用大多数标准的JS特性,例如XMLHttpRequest等;当然web workers也有不少局限行,例如不能操作DOM、作用域是独立的等等。

基本使用

下面来一起看一个简单的web workers例子。

我们首先创建一个 worker.js 的空文件。我们将在其中编写worker的代码。

然后我们通过 new Worker(workerFilePath) 的方式建立一个worker。

// index.html
const worker = new Worker('./worker.js');
复制代码

主线程和worker通过 postMessageonmessage 来通信。

首先,我们在主线程中通过 worker.postMessage 向worker发送消息。

// index.html
worker.postMessage('start');
复制代码

接着,我们在 worker.js 中定义 onmessage 来处理接收到的消息:

// worker.js
onmessage = function (ev) {
  if (ev.data === 'start') {
    timedCount();
  }
};
复制代码

onmessage 会收到一个 MessageEvent 事件作为参数,其中的 data 属性就是我们在 postMessage 中发送的数据。

同样的,我们可以在 worker.js 中使用 postMessage 向主线程发送消息:

// worker.js
const timedCount = function timedCount() {
  i += 1;
  postMessage(i);
  setTimeout(timedCount, 500);
};
复制代码

在主线程中我们通过 worker.onmessage 接受 worker 发来的消息,并可以调用 worker.terminate 来终止 worker

// index.html
worker.onmessage = function onmessage(ev) {
  document.getElementById('result').innerHTML = ev.data;
  if (ev.data === 10) worker.terminate();
};
复制代码

当然,我们可以使用 worker.js 创建多个worker:

// index.html
const worker1 = new Worker('./worker.js');
const worker2 = new Worker('./worker.js');
const anotherWorker = new Worker('./anotherWorker.js');
复制代码

importScript

我们可以使用 importScript 在web workers中引入其它代码, importScripts 是同步加载代码的,加载的代码中暴露的全局对象能够被worker使用,例如:

// worker.js
importScripts('./foo.js', './bar.js');

foo();
bar();

// foo.js
function foo() {
  console.log('foo');
};

// bar.js
function bar() {
  console.log('bar.js');
};

复制代码

注意这里引入代码的路径是与当前worker代码所在的路径对应的。

可转让对象(Transferable Objects)

由于在主线程和web workers之间传递数据需要经过拷贝过程,因此当我们在 postMessage 中发送大型数据时性能会收到影响。而可转让对象使得数据在上下文切换的过程中不必经过任何拷贝操作,从而大大提高了性能。

当数据被转移后,在原上下文中将被清除而不复存在:

// index.html
const worker = new Worker('./js/arrayBuffer.js');
const uInt8Array = new Uint8Array(1024); 
for (var i = 0; i < uInt8Array .length; ++i) {
  uInt8Array[i] = i;
}
worker.postMessage(uInt8Array.buffer, [uInt8Array.buffer]);
console.log(uInt8Array.byteLength); // 0

// arrayBuffer.js
onmessage = function (ev) {
  const uInt8View = new Uint8Array(ev.data);
  console.log(uInt8View.byteLength, uInt8View[11]);
};
复制代码

共享内存(Shared Memory)

共享内存是另一个使得主线程与web workers之前可以高效传递(共享)数据的方式。SharedArrayBuffer便是其实现。不过由于安全问题这一特性最终被关闭。

在webbpack中使用web worker

我们可以通过 worker-loader 来在webpack中使用web worker。

import Worker from 'worker-loader!./worker.js';

const worker = new Worker();
worker.postMessage('start');
worker.onmessage = function(ev) {};
复制代码

随后我们打包代码,在打包后的代码中我们应该可以看到类似下面的代码:

module.exports = function() {
  return new Worker(__webpack_require__.p + "61a1c1b143c4403de10b.worker.js");
};
复制代码

在这里可以看到 worker-loader 使用 new Worker(url) 的方式来加载web worker。

如果我们将以上的代码修改为:

import Worker from 'worker-loader?inline=true&fallback=false!./worker.js';
复制代码

并重新打包。这次我们将在 vendor.js (根据你的配置也可能是其他文件名)中找到类似如下的代码:

module.exports = function (content, url) {
  try {
    try {
      var blob;

      try {
        // BlobBuilder = Deprecated, but widely implemented
        var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder;

        blob = new BlobBuilder();

        blob.append(content);

        blob = blob.getBlob();
      } catch (e) {
        // The proposed API
        blob = new Blob([content]);
      }

      return new Worker(URL.createObjectURL(blob));
    } catch (e) {
      return new Worker('data:application/javascript,' + encodeURIComponent(content));
    }
  } catch (e) {
    if (!url) {
      throw Error('Inline worker is not supported');
    }

    return new Worker(url);
  }
};
复制代码

这里 worker-loader 会尝试通过 new Blob 以及 URL.createObjectURL 来将worker的代码内联,这里的 content 就是相应worker的代码文本。当然如果失败还是会回退为使用 url 加载web worker。

Shared worker

Shared worket提供了一种跨窗口/iframe等通信的途径。接下来我们用chrome来运行一下demo。

// index.html
<script type="text/javascript">
const id = (+new Date()).toString(32);

const myWorker = new SharedWorker('./js/shared.js');
myWorker.port.start();

myWorker.port.onmessage = function(ev) {
  const { type, id, data } = ev.data;
  switch(type) {
    case 'created':
      console.log(data);
      break;
  }
};

myWorker.port.postMessage({
  id,
  type: 'start',
});
</script>
复制代码

在页面上我们使用 (+new Date()).toString(32) 来将当前时间戳转换而成的字符串作为id(这里我们假设它的唯一性是有保障的)。

然后我们通过 new SharedWorker(filePath) 来加载shared worker,并且用 myWorker.port.start() 启动它。这会触发shared worker的 onconnect

接着我们通过 port.onmessage 设置消息接收回调,并使用 port.postMessage 向其发出一条消息。

const ids = [];
const ports = [];

const broadcast = function (data) {
  for (let port of ports) {
    port.postMessage(data);
  }
};

onconnect = function(e) {
  const port = e.ports[0];
  ports.push(port);

  port.addEventListener('message', (ev) => {
    const { type, id } = ev.data;
    switch(type) {
      case 'start':
        ids.push(id);
        broadcast({
          id,
          type: 'created',
          data: ids,
        });
        break;
    }
  });

  port.start();
};
复制代码

每当有shared worker接入,我们都在 onconnect 中将对应的 port 保存下来,这样我们就能实现广播机制。

我们通过 port.addEventListener('message', handler) 的方式添加接受消息的侦听,之后用 port.start() 启动它。

当我们收到 start 消息后,我们将新接入的信道的 id 保存下来,并这一消息广播出来(发送给所有已链接的 ports )。

如果我们先后在 chrome 浏览器中打开多个 tab 并打开我们的页面,就能看到新信道接入的消息被广播了。通过这样的方式,我们就能在多个窗口/iframe等之间实现通信了。


以上所述就是小编给大家介绍的《web workers简介(一)基础使用》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Just My Type

Just My Type

Simon Garfield / Profile Books / 2010-10-21 / GBP 14.99

What's your type? Suddenly everyone's obsessed with fonts. Whether you're enraged by Ikea's Verdanagate, want to know what the Beach Boys have in common with easy Jet or why it's okay to like Comic Sa......一起来看看 《Just My Type》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

html转js在线工具
html转js在线工具

html转js在线工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具