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简介(一)基础使用》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

网络共和国

网络共和国

[美] 凯斯·桑斯坦 / 黄维明 / 上海人民出版社 / 2003-6-1 / 15.00元

本书主要讨论网络中的民主问题。网络技术已经深刻地影响了我们的生活,我们随时可以获得我们需要的信息,我们也随时可以与别人联系,那么网络技术是不是就是民主的福音呢?作者回答说不,他认为通过网络人们更容易获得的是自己喜欢的信息,而拒绝接受自己不喜欢的信息,事实上人们得到的是窄化的信息,很多的网站也不和与自己立场相反的网站链接。而在一个真正的民主的环境中,信息应是多元的并且不是我们事先选择的,在其中我们还......一起来看看 《网络共和国》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

随机密码生成器
随机密码生成器

多种字符组合密码

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具