内容简介:大家好,今天在这里简单介绍一下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通过 postMessage
和 onmessage
来通信。
首先,我们在主线程中通过 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简介(一)基础使用》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Python基础--简介
- Flink入门基础 - 简介
- [基础算法]base64简介
- 数据管理流程,基础入门简介
- Python基础教程1:Python简介
- [译]WebRTC基础实践 - 1. WebRTC简介
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。