JS中worker如何与主线程通信?

前言

在JavaScript中,Web Workers提供了一种在后台运行脚本的方式,以便在主线程继续运行而不被阻塞。主线程与Worker之间的通信是通过事件来实现的。主线程可以向Worker发送数据,Worker可以向主线程发送数据。下面是关于如何实现主线程与Worker之间通信的几种方法:

1. 使用postMessage()方法:

window.postMessage() 方法可以安全地实现跨源通信。通常,对于两个不同页面的脚本,只有当执行它们的页面位于具有相同的协议(通常为 https),端口号(443https 的默认值),以及主机 (两个页面的域名 Document.domain设置为相同的值) 时,这两个脚本才能相互通信。window.postMessage() 方法提供了一种受控机制来规避此限制,只要正确的使用,这种方法就很安全。

更加详细信息:请查看MDN

// 主线程
const worker = new Worker('worker.js');
worker.postMessage('Hello from main thread!');

worker.onmessage = function(event) {
    console.log('Message from worker:', event.data);
};

// Worker (worker.js)
self.onmessage = function(event) {
    console.log('Message from main thread:', event.data);
    self.postMessage('Hello from worker!');
};

2. 使用MessageChannel:

Channel Messaging API 允许两个运行在同一个文档的不同浏览上下文(比如两个 iframe,或者文档主体和一个 iframe,使用 SharedWorker 的两个文档,或者两个 worker)中的独立脚本直接进行通讯,在每端使用一个端口(port)通过双向频道(channel)或管道(pipe)向彼此传递消息。

// 主线程
const worker = new Worker('worker.js');
const channel = new MessageChannel();

worker.postMessage({ port: channel.port1 }, [channel.port1]);

channel.port2.onmessage = function(event) {
    console.log('Message from worker:', event.data);
};

// Worker (worker.js)
self.onmessage = function(event) {
    const port = event.data.port;
    port.postMessage('Hello from worker!');
};

3. 共享ArrayBuffer(适用于大量数据的高性能通信):

SharedArrayBuffer 对象用来表示一个通用的原始二进制数据缓冲区,类似于 ArrayBuffer对象,但它可以用来在共享内存上创建视图。与可转移的 ArrayBuffer 不同,SharedArrayBuffer不是可转移对象。

什么是可以转移对象

可转移的对象(Transferable object)是拥有属于自己的资源的对象,这些资源可以从一个上下文转移到另一个,确保资源一次仅在一个上下文可用。传输后,原始对象不再可用;它不再指向转移后的资源,并且任何读取或者写入该对象的尝试都将抛出异常。

可转移对象通常用于共享资源,该资源一次仅能安全地暴露在一个 JavaScript 线程中。例如,ArrayBuffer 是一个拥有内存块的可转移对象。当此类缓冲区(buffer)在线程之间传输时,相关联的内存资源将从原始的缓冲区分离出来,并且附加到新线程创建的缓冲区对象中。原始线程中的缓冲区对象不再可用,因为它不再拥有属于自己的内存资源了。

SharedArrayBuffer 不是可转移对象,能够和主进程共享资源,直接附加在新线程创建的缓冲区对象中。

// 主线程
const sharedBuffer = new SharedArrayBuffer(16);
const sharedArray = new Int32Array(sharedBuffer);

const worker = new Worker('worker.js');
worker.postMessage(sharedArray);

// Worker (worker.js)
self.onmessage = function(event) {
    const sharedArray = event.data;
    sharedArray[0] = 42;
};

通过这些方法,主线程与Worker之间可以进行双向通信,实现数据的传递和处理。这样可以充分利用多线程的优势,提高JavaScript应用程序的性能和响应能力。

关于我
loading