无缝 Web 工作者和工作线程 -threads.js

2025-05-25

无缝 Web 工作者和工作线程 -threads.js

快速在 Worker 中运行跨平台 Javascript / TypeScript 代码。使用透明 API,省去繁琐步骤。

经过半年的测试,threads.js v1.0 终于发布了。它允许你以直观的方式使用 Web Worker 和工作线程,提供线程池等功能,可在 Web 客户端和 Node.js 中运行,并且大小不到 10kB!

使用工人的好处已经在很多其他文章中讨论过了,所以这里是要点:

  • 利用所有可用的 CPU 能力来运行繁重的 CPU 密集型任务
  • 将所有非渲染代码移出主线程,以确保流畅的动画和响应式的用户界面(Web Worker)
  • 隔离软件模块,限制它们通过消息传递进行通信

虽然 Web Worker 和 Worker 线程的 API 很相似,但遗憾的是它们并不完全兼容。此外,它们只是一些底层的构建块:创建 Worker、订阅消息、发送消息等等。

如果你向 Worker 发送一些消息,其中一条导致 Worker 抛出异常,会发生什么?调用代码很可能永远不会知道发生了错误——它只是不会收到响应消息而已。然后就是所有的粘合代码……

透明 API 的功能

进入正题……threads.js!让我们编写一个简单的工作器来为我们哈希密码。

// workers/auth.js
import sha256 from "js-sha256"
import { expose } from "threads/worker"

expose({
  hashPassword(password, salt) {
    return sha256(password + salt)
  }
})

现在让我们编写主线程的代码——生成一个新的工作者并对密码进行哈希处理。

// master.js
import { spawn, Thread, Worker } from "threads"

async function main() {
  const auth = await spawn(new Worker("./workers/auth"))
  const hashed = await auth.hashPassword("Super secret password", "1234")

  console.log("Hashed password:", hashed)

  await Thread.terminate(auth)
}

main().catch(console.error)

很简单。在 Worker 中暴露一个函数,然后从另一个线程调用它——搞定!

请注意auth.hashPassword(),无论最初是否返回承诺,都会hashPassword返回一个承诺 - 由于工作者通信的异步特性,返回值将被承诺化。

那么错误处理呢?这很简单,因为我们现在使用的是基于 Promise 的 API。

// master.js
import { spawn, Thread, Worker } from "threads"

async function main() {
  let auth, hashed

  try {
    auth = await spawn(new Worker("./workers/auth"))
  } catch (error) {
    // Cannot spawn the worker or crashed immediately before doing anything
  }

  try {
    hashed = await auth.hashPassword("Super secret password", "1234")
  } catch (error) {
    // Hashing this password failed
  }

  console.log("Hashed password:", hashed)

  await Thread.terminate(auth)
}

main().catch(console.error)

顺便问一下,你注意到了吗Thread.terminate()?我们使用它来终止一个工作进程。

在 node.js 中运行

现在,让我们将之前的示例代码中的 ES 模块import语句改为调用。你可以从这个 GitHub Gistrequire()克隆代码

$ git clone git@gist.github.com:925395687f42f6da04d111adf7d428ac.git ./threads-gist
$ cd threads-gist
$ npm install

运行它很简单。

$ node ./master

此代码将在任何带有工作线程支持的 node.js 版本中运行,因此 node 12+ 或 node 10+ 具有功能标志设置。

您甚至可以在 Node 8.12+ 上运行它。安装tiny-workernpm 包 - 如果工作线程不可用,threads.js 会自动将其作为 polyfill 加载。

使用 webpack 构建

很多人使用 webpack 打包代码以进行前端部署。那么,现在该如何使用 webpack 构建这些代码呢?

我们按原样使用我们的代码,采用我们的 webpack 配置并添加threads-plugin- 就是这样!

  // webpack.config.js
  const path = require("path")
+ const ThreadsPlugin = require("threads-plugin")

  module.exports = {
    entry: {
      app: "./src/index.js"
    },
    mode: "development",
    module: {
      rules: [
        {
          test: /\.css$/,
          use: ["style-loader", "css-loader"]
        },
        {
          test: /\.jsx?$/,
          use: ["babel-loader"]
        }
      ]
    },
    output: {
      path: path.join(__dirname, "dist")
    },
    plugins: [
      new HtmlPlugin(),
+     new ThreadsPlugin()
    ]
  }

该插件基于 Google 的worker-plugin- 它将识别new Worker()表达式,确保引用的工作文件独立于主入口点捆绑,并将表达式中的路径重写new Worker()为工作包路径。

一流的 TypeScript 支持

Threads.js 是用 TypeScript 编写的,因此完全是静态类型的,因此 IDE 的 IntelliSense 会在您编写时显示所有可用的导出、函数和参数,并附带文档。不仅如此,运行 TypeScript Worker 也变得更加轻松。

在 node.js 中运行 TypeScript 代码时,您会经常发现自己ts-node在开发中使用并在生产中运行转换后的 JavaScript 代码。

在解析 Worker 时,threads.js 会尝试加载已转译的 JavaScript Worker。如果失败且ts-node已安装,它将自动进行故障转移,使用 运行未转译的 TypeScript Worker 文件ts-node。你无需费力 🙌

线程池、可观察对象等

还有更多值得探索!

  • 线程池用于生成多个工作线程并向其分配任务
  • 返回可观察对象以公开要订阅的事件
  • 支持可传输对象以高效传递二进制数据
  • 以及更多…🚀

您可以在threads.js.org上找到详细文档

未来还会有更多功能。您可以查看GitHub 仓库及其问题,了解当前正在讨论的内容,或者关注仓库的发布情况,了解最新动态。


今天就到这里——希望你喜欢这篇博文。如果你喜欢这个项目,请在 GitHub 上给代码库点个赞,为开发做出贡献,或者成为赞助商

欢迎在下面发表评论并留下任何类型的反馈。

节日快乐,黑客攻击愉快!

安迪

预告图片由 Adi Goldstein 在 Unsplash 上发布

文章来源:https://dev.to/andywer/seamless-web-workers-worker-threads-threads-js-2g36
PREV
DevOps 的 Git 分支策略:协作的最佳实践简介了解 Git 分支 Git 分支策略选择正确的策略协作的最佳实践有用的链接结论
NEXT
我希望在开始我的计算机科学专业时就知道编程职业的四件事