JS中worker如何与主线程通信?
前言
在JavaScript中,Web Workers提供了一种在后台运行脚本的方式,以便在主线程继续运行而不被阻塞。主线程与Worker之间的通信是通过事件来实现的。主线程可以向Worker发送数据,Worker可以向主线程发送数据。下面是关于如何实现主线程与Worker之间通信的几种方法:
1. 使用postMessage()方法:
window.postMessage()
方法可以安全地实现跨源通信。通常,对于两个不同页面的脚本,只有当执行它们的页面位于具有相同的协议(通常为 https
),端口号(443
为 https
的默认值),以及主机 (两个页面的域名 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应用程序的性能和响应能力。