Web Workers 教程:了解 Javascript Web Workers 的工作原理

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 添加新项目。