Baike.dev
All toolsOnline toolsAI codingTrendingOpen sourceNewsSubmit
Log in
< Back to tools
N

node-webworker-threads

> 编程语言
Open source

Lightweight Web Worker API implementation with native threads

2.3K stars0 likes1 views
WebsiteGitHub

About

Lightweight Web Worker API implementation with native threads

WebWorker Threads

This is based on @xk (jorgechamorro)'s Threads A GoGo for Node.js, but with an API conforming to the Web Worker standard.

This module provides an asynchronous, evented and/or continuation passing style API for moving blocking/longish CPU-bound tasks out of Node's event loop to JavaScript threads that run in parallel in the background and that use all the available CPU cores automatically; all from within a single Node process.

Note: If you would like to require() native modules in a worker, please consider using the process-based tiny-worker instead. It does not use threads, but the WebWorker API is compatible.

This module requires Node.js 0.10.0+ and a working node-gyp toolchain.

Illustrated Writeup

There is an illustrated writeup for the original use case of this module:

Installing the module

With npm:

bash
npm install webworker-threads

Sample usage (adapted from MDN):

javascript
var Worker = require('webworker-threads').Worker;
// var w = new Worker('worker.js'); // Standard API

// You may also pass in a function:
var worker = new Worker(function(){
  postMessage("I'm working before postMessage('ali').");
  this.onmessage = function(event) {
    postMessage('Hi ' + event.data);
    self.close();
  };
});
worker.onmessage = function(event) {
  console.log("Worker said : " + event.data);
};
worker.postMessage('ali');

A more involved example in LiveScript syntax, with five threads:

coffee
{ Worker } = require \webworker-threads

for til 5 => (new Worker ->
  fibo = (n) -> if n > 1 then fibo(n - 1) + fibo(n - 2) else 1
  @onmessage = ({ data }) -> postMessage fibo data
)
  ..onmessage = ({ data }) ->
    console.log "[#{ @thread.id }] #data"
    @postMessage Math.ceil Math.random! * 30
  ..postMessage Math.ceil Math.random! * 30

do spin = -> setImmediate spin

Introduction

After the initialization phase of a Node program, whose purpose is to setup listeners and callbacks to be executed in response to events, the next phase, the proper execution of the program, is orchestrated by the event loop whose duty is to juggle events, listeners and callbacks quickly and without any hiccups nor interruptions that would ruin its performance.

Both the event loop and said listeners and callbacks run sequentially in a single thread of execution, Node's main thread. If any of them ever blocks, nothing else will happen for the duration of the block: no more events will be handled, no more callbacks nor listeners nor timeouts nor setImmediate()ed functions will have the chance to run and do their job, because they won't be called by the blocked event loop, and the program will turn sluggish at best, or appear to be frozen and dead at worst.

What is WebWorker-Threads

webworker-threads provides an asynchronous API for CPU-bound tasks that's missing in Node.js:

javascript
var Worker = require('webworker-threads').Worker;
require('http').createServer(function (req,res) {
  var fibo = new Worker(function() {
    function fibo (n) {
      return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;
    }
    this.onmessage = function (event) {
      postMessage(fibo(event.data));
    }
  });
  fibo.onmessage = function (event) {
    res.end('fib(40) = ' + event.data);
  };
  fibo.postMessage(40);
}).listen(port);

And it won't block the event loop because for each request, the fibo worker will run in parallel in a separate background thread.

API

Module API

javascript
var Threads= require('webworker-threads');
.Worker

new Threads.Worker( [ file | function ] ) returns a Worker object.

.create()

Threads.create( /* no arguments */ ) returns a thread object.

.createPool( numThreads )

Threads.createPool( numberOfThreads ) returns a threadPool object.


Web Worker API

javascript
var worker= new Threads.Worker('worker.js');
var worker= new Threads.Worker(function(){ ... });
var worker= new Threads.Worker();
.postMessage( data )

worker.postMessage({ x: 1, y: 2 }) sends a data structure into the worker. The worker can receive it using the onmessage handler.

.onmessage

worker.onmessage = function (event) { console.log(event.data) }; receives data from the worker's postMessage calls.

.terminate()

worker.terminate() terminates the worker thread.

.addEventListener( type, cb )

worker.addEventListener('message', callback) is equivalent to setting worker.onmesssage = callback.

.dispatchEvent( event )

Currently unimplemented.

.removeEventListener( type )

Currently unimplemented.

.thread

Returns the underlying thread object; see the next section for details. Note that this attribute is implementation-specific, and not part of W3C Web Worker API.


Thread API

javascript
var thread= Threads.create();
.id

thread.id is a sequential thread serial number.

.load( absolutePath [, cb] )

thread.load( absolutePath [, cb] ) reads the file at absolutePath and thread.eval(fileContents, cb).

.eval( program [, cb])

thread.eval( program [, cb]) converts program.toString() and eval()s it in the thread's global context, and (if provided) returns the completion value to cb(err, completionValue).

.on( eventType, listener )

thread.on( eventType, listener ) registers the listener listener(data) for any events of eventType that the thread thread may emit.

.once( eventType, listener )

thread.once( eventType, listener ) is like thread.on(), but the listener will only be called once.

.removeAllListeners( [eventType] )

thread.removeAllListeners( [eventType] ) deletes all listeners for all eventTypes. If eventType is provided, deletes all listeners only for the event type eventType.

.emit( eventType, eventData [, eventData ... ] )

thread.emit( eventType, eventData [, eventData ... ] ) emits an event of eventType with eventData inside the thread thread. All its arguments are .toString()ed.

.destroy( /* no arguments */ )

thread.destroy( /* no arguments */ ) destroys the thread.


Thread pool API

javascript
threadPool= Threads.createPool( numberOfThreads );
.load( absolutePath [, cb] )

threadPool.load( absolutePath [, cb] ) runs thread.load( absolutePath [, cb] ) in all the pool's threads.

.any.eval( program, cb )

threadPool.any.eval( program, cb ) is like thread.eval(), but in any of the pool's threads.

.any.emit( eventType, eventData [, eventData ... ] )

threadPool.any.emit( eventType, eventData [, eventData ... ] ) is like thread.emit(), but in any of the pool's threads.

.all.eval( program, cb )

threadPool.all.eval( program, cb ) is like thread.eval(), but in all the pool's threads.

.all.emit( eventType, eventData [, eventData ... ] )

threadPool.all.emit( eventType, eventData [, eventData ... ] ) is like thread.emit(), but in all the pool's threads.

.on( eventType, listener )

threadPool.on( eventType, listener ) is like thread.on(), but in all of the pool's threads.

.totalThreads()

threadPool.totalThreads() returns the number of threads in this pool: as supplied in .createPool( number )

.idleThreads()

threadPool.idleThreads() returns the number of threads in this pool that are currently idle (sleeping)

.pendingJobs()

threadPool.pendingJobs() returns the number of jobs pending.

.destroy( [ rudely ] )

threadPool.destroy( [ rudely ] ) waits until pendingJobs() is zero and then destroys the pool. If rudely is truthy, then it doesn't wait for pendingJobs === 0.


Global Web Worker API

Inside every Worker instance from webworker-threads, there's a global self object with these properties:

.postMessage( data )

postMessage({ x: 1, y: 2 }) sends a data structure back to the main thread.

.onmessage

onmessage = function (event) { ... } receives data from the main thread's .postMessage calls.

.close()

close() stops the current thread.

.addEventListener( type, cb )

addEventListener('message', callback) is equivalent to setting self.onmesssage = callback.

.dispatchEvent( event )

dispatchEvent({ type: 'message', data: data }) is the same as self.postMessage(data).

.removeEventListener( type )

Currently unimplemented.

.importScripts( file [, file...] )

importScripts('a.js', 'b.js') loads one or more files from the disk and eval() them in the worker's instance scope.

.thread

The underlying thread object; see the next section for details. Note that this attribute is implementation-specific, and not part of W3C Web Worker API.


Global Thread API

Inside every thread .create()d by webworker-threads, there's a global thread object with these properties:

.id

thread.id is the serial number of this thread

.on( eventType, listener )

thread.on( eventType, listener ) is just like thread.on() above.

.once( eventType, listener )

thread.once( eventType, listener ) is just like thread.once() above.

.emit( eventType, eventData [, eventData ... ] )

thread.emit( eventType, eventData [, eventData ... ] ) is just like thread.emit() above.

.removeAllListeners( [eventType] )

thread.removeAllListeners( [eventType] ) is just like thread.removeAllListeners() above.

.nextTick( function )

thread.nextTick( function ) is like process.nextTick(), but much faster.


Global Helper API

Inside every thread .create()d by webworker-threads, there are some helpers:

console.log(arg1 [, arg2 ...])

Same as console.log on the main process.

console.error(arg1 [, arg2 ...])

Same as console.log, except it prints to stderr.

puts(arg1 [, arg2 ...])

puts(arg1 [, arg2 ...]) converts .toString()s and prints its arguments to stdout.

Developer guide

See the developer guide if you want to contribute.


WIP WIP WIP

Note that everything below this line is under construction and subject to change.

Examples

A.- Here's a program that makes Node's event loop spin freely and as fast as possible: it simply prints a dot to the console in each turn:

cat examples/quickIntro_loop.js
javascript
(function spinForever () {
  setImmediate(spinForever);
})();

B.- Here's another program that adds to the one above a fibonacci(35) call in each turn, a CPU-bound task that takes quite a while to complete and that blocks the event loop making it spin slowly and clumsily. The point is simply to show that you can't put a job like that in the event loop because Node will stop performing properly when its event loop can't spin fast and freely due to a callback/listener/setImmediate()ed function that's blocking.

cat examples/quickIntro_blocking.js
javascript
function fibo (n) {
  return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;
}

(function fiboLoop () {
  process.stdout.write(fibo(35).toString());
  setImmediate(fiboLoop);
})();

(function spinForever () {
  setImmediate(spinForever);
})();

C.- The program below uses webworker-threads to run the fibonacci(35) calls in a background thread, so Node's event loop isn't blocked at all and can spin freely again at full speed:

cat examples/quickIntro_oneThread.js
javascript
function fibo (n) {
  return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;
}

function cb (err, data

Issues· 0 open

View all issuesOpen on GitHub

No open issues yet, or sync has not completed.

> Tags

C++

No comments yet. Be the first to share.

> Details

PublishedAug 1, 2026
UpdatedSep 17, 2026
Category编程语言
PricingOpen source

> Related tools

T
TypeScript
JavaScript 的超集,为前端与全栈提供静态类型
P
Python
通用编程语言,广泛用于 Web、数据与 AI
G
Go
Google 推出的简洁高效系统语言