Javascript 是一种单线程语言。这意味着 Javascript 在一个进程上运行。它在您的代码中一次只能做一件事。
这通常很好,因为 Javascript 非常快。但有时,它还不够快。当我们想要同时运行多个进程时,我们必须使用web workers。
Web Workers 什么时候有用?#
在复杂的大型应用程序中,Javascript 只能从上到下运行您尝试使用的文件或函数。如果我们在彼此之上进行大量高计算过程,则可能会出现问题。
想象一个简单的图像上传网站,它可以识别照片中的对象。您上传图像,然后通过复杂的算法对图像进行处理以识别帧中的对象。由于 Javascript 是单线程的,因此网站将暂停,直到该处理完成。
如果我们在第二个线程上运行处理,用户仍然可以交互和使用网站,同时等待处理完成。
正如你在上面看到的,web workers让我们并行运行两段代码。
web workers..如何工作?#
Web Worker 并没有你想象的那么复杂。下面是一个使用 vanilla 前端 Javascript 构建的简单 Web Worker 示例。让我们看看它是如何工作的。
main.js
let myWebWorker = new Worker('./thread.js'); document.getElementById('button').addEventListener('click', function(e) { myWebWorker.postMessage({ "message" : "outcome" }); }); myWebWorker.onmessage = (e) => { console.log(`Message received from web worker.. Message is ${e.data}`); } myWebWorker.onerror = (error) => { console.log(`We ran into an error with your web worker.. Error is ${error}`); }
thread.js
onmessage = (e) => { postMessage(e.data); }
在main.js中,当用户单击按钮时,将向我们的 web worker 发布一条消息,该 web worker 位于thread.js中。此消息可以采用各种格式,包括 Blob、文件、对象、数组、文本或数字。
在thread.js中,我们有一个 onmessage 事件处理程序,它将处理来自我们的main.js文件的数据。我们可以使用 访问数据data
,其中将包含我们使用 postMessage( { "message" : "outcome" }
) 发送的对象。
最后,当thread.js文件使用 postMessage 时,我们可以在main.js中使用myWebWorker.onmessage
. 然后我们可以将 web worker 处理的结果显示给用户。在这种情况下,我们刚刚控制台记录了原始消息。
Web Worker 如何在 Node.JS 中工作#
Node.JS 有一些细微的差异,我们将在此处介绍。本质上,我们必须导入网络工作者以使其正常工作:
main.js
// Web Workers import { Worker, isMainThread, parentPort, workerData } from 'worker_threads'; const worker = new Worker('./thread.js'); // Post a message worker.postMessage("Hello"); // Wait for an output worker.on('message', function(result) { console.log(result); }); // Capture any errors worker.on('error', function(result) { console.log(error); });
thread.js
import { workerData, parentPort } from 'worker_threads'; parentPort.on('message', function(data) { parentPort.postMessage("Goodbye"); });
Node.JS 和 vanilla Javascript 之间的一个主要区别是我们使用on()
函数,而不是onmessage
. 同样,我们收到的数据可以直接使用,而无需使用e.data
,所以我们可以调用e
来取回我们的数据。
Web Workers 中的全局对象#
通常在网络上,当我们想要引用全局对象时,我们会引用window
,self
或者最近globalThis
的 . 在 webworkers 中,我们引用window
对象等价物的方式是使用self
.
self.someVariable = 'name'
web workers的局限性是什么?#
Web Worker 有一些限制,使其与典型的 Javascript 不同:
- 你不能操纵 DOM 元素。
- 您无法创建新元素。
- 您无法加载图像。
尽管 web worker 有所有这些限制,我们仍然可以将密集的任务外包给 web worker,当他们发送响应时,我们可以在主线程 Javascript 中向 DOM 添加新项目。