Package Exports
- @bitair/concurrent.js
- @bitair/concurrent.js/worker_script
Readme
NOT READY FOR PRODUCTION
Intro
Concurrent.js helps with concurrent computation in JavaScript runtime environments. It can run CPU-intensive operations without blocking the main thread. Concurrent.js is designed to load JavaScript modules into workers and access them as usual. It provides a "write less, do more" isomorphic API and works on Node.js, Deno, and web browsers.
Features
- Loading CommonJS modules into workers
- Loading ECMAScript modules
- Accessing exported classes
- Instantiation
- Instance members
- Methods
- Getters and setters
- Fields
- Static members
- Methods
- Getters and setters
- Fields
- Accessing exported functions
- Loading WebAssembly
- Supporting Node.js
- Supporting web browsers
- Supporting Deno
- Reactive multithreading
- Sandboxing
Install
npm i -S @bitair/concurrent.js
Hello World!
Let's assume that we have a calculator module with a prime number checker:
// calculator.js
export class Calculator {
isPrime(n) {
const j = Math.sqrt(n)
for (let i = 2; i <= j; i++) {
if (n % i === 0) return false
}
return n > 1
}
}
In order to run it without blocking the main thread:
Instead of using
require
orimport
functions use theload
method with the module's absolute path or URL:const { Calculator } = await concurrent.load(CALCULATOR_MODULE_SRC)
Instantiate an object of an exported class/constructor in the usual way:
const calculator = new Calculator()
Invoke any method of the instance. This should be done asynchronously (e.g. using the
await
operator):const result = await calculator.isPrime(123456789)
Explicitly delete the instance before leaving its scope (this will be automated by implementing a garbage collector in later versions):
await concurrent.dispose(calculator)
Terminate Concurrent.js before exiting the app:
await concurrent.terminate()
Please see the sample projects for a complete code. In order to run a sample project:
cd SAMPLE_DIR
npm i
npm build
npm start
Client-side usage
A client-side app should consist of three scripts/bundles:
- One that contains the app's code
- Another one that contains the concurrent modules' code
- A
worker_script.js
bundle that must be generated from the following code:import '@bitair/concurrent.js/worker_script'
Parallelism
In order to achieve parallelism, the number of total workers must be less than or equal to the total available CPUs/cores. In Node.js v19.4.0 or later the number can be extracted from os.availableParallelism.
The load method has a flag named isolated
that tells Concurrent.js to allocate an individual worker to every instance of an object and to every invocation of a function (function indicates an exported function not a method of an instance):
import concurrent from '@bitair/concurrent.js'
concurrent.config({
maxThreads: 16
})
const { Calculator } = await concurrent.load(
new URL('./sample_services/index.js', import.meta.url),
{
isolated: true
}
)
const ops = []
for (let i = 0; i <= 20; i++) {
const calculator = new Calculator()
ops.push(
Promise.resolve(calculator.isPrime(i)).then(async result => {
// The 17th operation will be waiting for a worker to be released.
// So removing the next line will freeze the app
await dispose(calculator)
return result
})
)
}
const results = await Promise.all(ops)
// ...rest of the code
API
IN PROGRESS
Notes
- All concurrent methods and functions must be called asynchronously.
- The data that would be sent to or received from concurrent instances/functions must be supported by the structured clone algorithm .
- Workers can't run TypeScript. So in case of using tools like
ts-node
the load method would perform a normal import using the dynamic import function. - All unhandled exceptions would be bubbled up to the main thread.
- Every function call and object instantiation would be run on an individual worker if available or share a worker if the isolated flag is not enabled.
- When using Concurrent.js on the client side the app and its concurrent modules should be bundled separately in order to not load the entire app inside a worker.