Runs an instance1 across multiple processes, allowing for parallel computation. Works both in the browser and in Node.js.
Define methods that change the state (commands) and others that do not (queries). Two different queries can be run at the same time, whereas two different commands cannot.
Suppose you have a file called my-state-worker-script.js
whose content looks something like this:
queries = {
getDifference(y){
return this.state.x - y;
}
};
commands = {
setX(value){
this.state.x = value;
}
};
Now you can create a StateWorker
like this:
// supposing we are inside a function marked `async`
const stateWorker = await StateWorker.create(
{
path: 'my-state-worker-script.js',
maxNumberOfProcesses: 3
});
// execute the command
await stateWorker.setX(4);
// logs `1`
console.log(await stateWorker.getDifference(3))
Exactly the same, except that the script now has to export the commands and the queries in a commonjs way:
const commands = { /* the methods that should be treated like commmands */ };
const queries = { /* the methods that should be treated like queries */ };
module.exports = { commands, queries };
There are three test scripts: test-units
, test-node
and test-web
. The first runs unit tests. The second relies on state-worker.js
having been built and put in the dist
folder (by running build
or build-dev
) and then tests it in an actual Node environment, creating child processes and everything. The third also relies on the build result in the dist
folder, but then uses Karma to run StateWorker
in an actual browser, where it (i.e. StateWorker
) will create Workers. The fourth test script, test
, runs test-units
, then builds StateWorker
and finally runs the second and third scripts.
StateWorker.create(config)
- config (Config)
- returns: a
Promise
that will resolve to an instance of aStateWorker
(or reject).
Properties:
maxNumberOfProcesses
(number): the maximum number of processes (web workers in the browser, worker threads in Node) that will be createdpath
(string): the path to the file that contains the definitions of the methods (queries and commands). In the browser, this path should either be relative to the document's baseURI, or absolute. In a Node context, it should be absolute.module
(boolean): in the context of a browser, signifies whether the script should be loaded into the web worker as a module 2gracefulQueryCancellation
: ifStateWorker
is currently running a query on some instance, but a command is waiting to be executed (which will always cause any running query to reject), and if this property is set tofalse
, this means thatStateWorker
will not wait for the instance that is running the query to become idle, but will simply terminate the instance in question, so as to be able to begin execution of the command sooner. IfgracefulQueryCancellation
is not set, or it is set totrue
, an instance that is currently running a query that was already cancelled because of a command will not be terminated, but will be allowed to become idle before the command is run.
Methods:
terminate()
: terminates all child processes and causes all running queries or commands to reject
In addition to terminate
, an instance of StateWorker
will have a method for each command and for each query that is defined in the script. Each of these methods will return a Promise
.
A method in the StateWorker
script may reference this
. this
will have the following methods:
await(promise)
promise
(object): if it really is aPromise
, the current instance (web worker, worker script, whatever the case may be) will tell theStateWorker
that it is now free to do something else (run another query, perhaps) as long aspromise
has not resolved yet.- returns: a
Promise
that will resolve oncepromise
has resolved and the current instance is not doing anything else
Example:
queries = {
async longRunningQuery(){
// ... do work here, and then:
const promise = /* some task that will complete in the future */
// now this instance is free to do something else until `promise` resolves, so we release it:
const result = await this.await(promise);
// and now `promise` has resolved and `result` is its result
}
};