Top Related Projects
Quick Overview
threads.js is a lightweight JavaScript library that provides a simple way to run CPU-intensive tasks in separate threads using Web Workers. It allows developers to easily offload heavy computations to background threads, improving the performance and responsiveness of web applications.
Pros
- Easy to use API for creating and managing worker threads
- Supports both Node.js and browser environments
- Provides a seamless way to handle asynchronous operations with Promises
- Lightweight and has minimal dependencies
Cons
- Limited to JavaScript-based tasks (cannot execute native code)
- May have a slight overhead for creating and managing threads
- Not suitable for very short-lived or frequently created tasks due to thread creation cost
- Requires careful consideration of data sharing and synchronization between threads
Code Examples
Creating a worker thread:
import { spawn, Thread, Worker } from 'threads'
const worker = await spawn(new Worker('./worker'))
const result = await worker.heavyComputation(data)
await Thread.terminate(worker)
Defining a worker:
import { expose } from 'threads/worker'
expose({
heavyComputation(data) {
// Perform CPU-intensive task here
return result
}
})
Using pool of workers:
import { Pool } from 'threads'
const pool = Pool(() => spawn(new Worker('./worker')), 4)
const results = await Promise.all([
pool.queue(worker => worker.heavyComputation(data1)),
pool.queue(worker => worker.heavyComputation(data2))
])
await pool.terminate()
Getting Started
-
Install the library:
npm install threads
-
Create a worker file (e.g.,
worker.js
):import { expose } from 'threads/worker' expose({ heavyComputation(data) { // Your CPU-intensive code here return result } })
-
Use the worker in your main script:
import { spawn, Thread, Worker } from 'threads' async function main() { const worker = await spawn(new Worker('./worker')) const result = await worker.heavyComputation(data) console.log(result) await Thread.terminate(worker) } main().catch(console.error)
Competitor Comparisons
Build system optimized for JavaScript and TypeScript, written in Rust
Pros of Turborepo
- Designed for monorepo management with built-in task orchestration and caching
- Offers powerful build pipeline optimization and dependency graph analysis
- Integrates well with popular JavaScript frameworks and build tools
Cons of Turborepo
- Steeper learning curve due to its comprehensive feature set
- May be overkill for smaller projects or those not using a monorepo structure
- Requires more configuration and setup compared to simpler threading libraries
Code Comparison
Threads.js:
import { spawn, Thread, Worker } from "threads"
const worker = await spawn(new Worker("./worker"))
const result = await worker.doWork()
await Thread.terminate(worker)
Turborepo:
{
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", ".next/**"]
},
"test": {
"dependsOn": ["build"],
"outputs": []
}
}
}
Summary
Turborepo is a comprehensive monorepo management tool with advanced build optimization features, while Threads.js focuses on simplifying multi-threading in JavaScript. Turborepo excels in large, complex projects with multiple packages, whereas Threads.js is more suitable for adding concurrency to specific parts of an application. The choice between them depends on project scale, structure, and specific threading needs.
A fast, efficient Node.js Worker Thread Pool implementation
Pros of Piscina
- Built-in worker pool management for efficient resource utilization
- Supports both ESM and CommonJS modules out of the box
- Integrated with Node.js core APIs for better performance
Cons of Piscina
- Limited to Node.js environment, not suitable for browser use
- Steeper learning curve due to more advanced features
- Less focus on TypeScript support compared to threads.js
Code Comparison
threads.js:
import { spawn, Thread, Worker } from 'threads'
const worker = await spawn(new Worker('./worker'))
const result = await worker.doWork()
await Thread.terminate(worker)
Piscina:
import Piscina from 'piscina'
const pool = new Piscina()
const result = await pool.run({ filename: './worker.js' })
await pool.destroy()
Both libraries aim to simplify working with worker threads in Node.js, but they have different approaches. threads.js provides a more straightforward API with better TypeScript integration, making it easier for developers familiar with Promise-based programming. Piscina, on the other hand, offers more advanced features like built-in worker pool management and better integration with Node.js core APIs, which can lead to improved performance in certain scenarios. The choice between the two depends on the specific requirements of your project and your familiarity with worker thread concepts.
Napa.js: a multi-threaded JavaScript runtime
Pros of Napajs
- Developed and maintained by Microsoft, potentially offering better long-term support and resources
- Designed for multi-threaded JavaScript in Node.js, providing better performance for CPU-intensive tasks
- Supports shared memory between threads, allowing for more efficient data sharing
Cons of Napajs
- Less active development and maintenance (last commit in 2019)
- More complex API and setup compared to threads.js
- Limited compatibility with newer Node.js versions
Code Comparison
threads.js:
const { spawn, Thread, Worker } = require('threads');
const worker = await spawn(new Worker('./worker'));
const result = await worker.doWork();
await Thread.terminate(worker);
Napajs:
const napa = require('napajs');
const zone = napa.zone.create('zone', { workers: 4 });
zone.execute(() => {
// Worker code here
}).then((result) => {
console.log(result);
});
Both libraries aim to provide multi-threading capabilities for JavaScript, but they differ in their approach and implementation. threads.js offers a simpler API and is more actively maintained, making it easier to use for developers who need basic multi-threading functionality. Napajs, on the other hand, provides more advanced features like shared memory and is designed for high-performance scenarios, but requires a more complex setup and has less recent development activity.
Convert
designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
Offload CPU-intensive tasks to worker threads in node.js, web browsers and electron using one uniform API.
Uses web workers in the browser, worker_threads
in node 12+ and tiny-worker
in node 8 to 11.
Features
- First-class support for async functions & observables
- Write code once, run it on all platforms
- Manage bulk task executions with thread pools
- Use require() and import/export in workers
- Works great with webpack
Version 0.x
You can find the old version 0.12 of threads.js on the v0
branch. All the content on this page refers to version 1.0 which is a rewrite of the library with a whole new API.
Installation
npm install threads tiny-worker
You only need to install the tiny-worker
package to support node.js < 12. It's an optional dependency and used as a fallback if worker_threads
are not available.
Platform support
Run on node.js
Running code using threads.js in node works out of the box.
Note that we wrap the native Worker
, so new Worker("./foo/bar")
will resolve the path relative to the module that calls it, not relative to the current working directory.
That aligns it with the behavior when bundling the code with webpack or parcel.
Webpack build setup
Webpack config
Use with the threads-plugin
. It will transparently detect all new Worker("./unbundled-path")
expressions, bundles the worker code and replaces the new Worker(...)
path with the worker bundle path, so you don't need to explicitly use the worker-loader
or define extra entry points.
npm install -D threads-plugin
Then add it to your webpack.config.js
:
+ const ThreadsPlugin = require('threads-plugin');
module.exports = {
// ...
plugins: [
+ new ThreadsPlugin()
]
// ...
}
Node.js bundles
If you are using webpack to create a bundle that will be run in node (webpack config target: "node"
), you also need to specify that the tiny-worker
package used for node < 12 should not be bundled:
module.exports = {
// ...
+ externals: {
+ "tiny-worker": "tiny-worker"
+ }
// ...
}
Make sure that tiny-worker
is listed in your package.json
dependencies
in that case.
When using TypeScript
Note: You'll need to be using Typescript version 4+, as the types generated by threads.js are not supported in Typescript 3.
Make sure the TypeScript compiler keeps the import
/ export
statements intact, so webpack resolves them. Otherwise the threads-plugin
won't be able to do its job.
module.exports = {
// ...
module: {
rules: [
{
test: /\.ts$/,
loader: "ts-loader",
+ options: {
+ compilerOptions: {
+ module: "esnext"
+ }
+ }
}
]
},
// ...
}
Parcel bundler setup
You need to import threads/register
once at the beginning of your application code (in the master code, not in the workers):
import { spawn } from "threads"
+ import "threads/register"
// ...
const work = await spawn(new Worker("./worker"))
This registers the library's Worker
implementation for your platform as the global Worker
. This is necessary, since you cannot import { Worker } from "threads"
or Parcel won't recognize new Worker()
as a web worker anymore.
Be aware that this might affect any code that tries to instantiate a normal web worker Worker
and now instead instantiates a threads.js Worker
. The threads.js Worker
is just a web worker with some sugar on top, but that sugar might have unexpected side effects on third-party libraries.
Everything else should work out of the box.
Getting Started
Basics
// master.js
import { spawn, Thread, Worker } from "threads"
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)
// workers/auth.js
import sha256 from "js-sha256"
import { expose } from "threads/worker"
expose({
hashPassword(password, salt) {
return sha256(password + salt)
}
})
spawn()
The hashPassword()
function of the auth
object in the master code proxies the call to the hashPassword()
function in the worker:
If the worker's function returns a promise or an observable then you can just use the return value as such in the master code. If the function returns a primitive value, expect the master function to return a promise resolving to that value.
expose()
Use expose()
to make a function or an object containing methods callable from the master thread.
In case of exposing an object, spawn()
will asynchronously return an object exposing all the object's functions. If you expose()
a function, spawn
will also return a callable function, not an object.
Usage
Find the full documentation on the website:
Webpack
Threads.js works with webpack. Usually all you need to do is adding the
threads-plugin
.
See Build with webpack on the website for details.
Debug
We are using the debug
package to provide opt-in debug logging. All the package's debug messages have a scope starting with threads:
, with different sub-scopes:
threads:master:messages
threads:master:spawn
threads:master:thread-utils
threads:pool:${poolName || poolID}
Set it to DEBUG=threads:*
to enable all the library's debug logging. To run its tests with full debug logging, for instance:
DEBUG=threads:* npm test
License
MIT
Top Related Projects
Convert
designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot