thread.js
thread.js is lightweight, reliable and rich featured library that simplifies JavaScript parallel computing in browser environments through a clean and elegant API with promise-based asynchronous handling. You can run tasks in a real thread in a really simple way, with an elegant programatic aproach and great state handling
It provides awesome features such as data binding serialization, cross-scope arguments passing, asynchronous tasks, require external sources easly in the thread and includes built-in support for creating pool of threads to distribute the task load across multiple workers transparently using a simple best availability task schedule algorithm
It uses Web Workers to create real threads,
but provides fallback support for older browsers based on an iframe
hack (now you can be safe in IE9 and other older browsers)
Welcome to the multithreading world in the browser, now made simple and small (5KB gzipped)
Getting started with basic usage, some examples or tests and be aware about threads limitations
Installation
Via Bower
bower install thread
Via Component
component install h2non/thread.js
Or loading the script remotely
Browser Support
+4 | +3.5 | +10 | +10.6 | +7 |
Basic usage
If require
is available, you must use it to fetch the module.
Otherwise it will be available as global
var thread =
Create a new thread with custom scope environment and import external libraries
var worker =
Running a synchronous task in the thread
var task = worker
Running an asynchronous task in the thread
var task = worker
Consuming the computed result (promise-based API)
task
Note about Internet Explorer usage
Since Microsoft makes a continuous effort to break the Web and its standards, due to a technical limitation in IE 10 and 11, it is required to use an external script to create the thread properly.
You must customize the evalPath
option when creating threads from IE.
The eval script is located in lib/eval.js
Common example with Bower:
var worker =
If you use full URLs to load the eval
script, be aware about cross-origin policy.
You must define the CORS headers properly in the server
Web Workers resources
Threads limitations
You should be aware of some limitations while using threads
Threads has its own isolated scope, so that means each thread has its own memory space. That's means you must explicitly bind values or functions to the thread in order to consum them inside the thread scope. Any passed value to the thread scope will be cloned (it will be passed by value, not by reference), so mutation is not possible between scopes since memory space has no synchronization
If you create a pool of threads, you must consider that threads in the pool are scope-isolated too. In other words, it's not supported scope synchronization between threads in the pool. That's usually positive because you cannot have side-effects between threads, but you should be aware about global scope dependencies and mutation in your code in other to avoid inconsistency between threads
All values binded to the thread must be JSON-serializable, meaning only primitives types, raw objects and functions. Same with return values from threads.
In modern browsers, there is possible to bind complex data type structures to the Worker scope using the Transferable interface which supports the internal structure cloning algorithm. However, there are still some limitations: DOM nodes, native built-in functions and prototypes chains cannot be cloned and therefore, is not possible to bind them to the thread
Additionally, threads do not have access to the DOM API
API
thread([options])
Return: thread
Alias: thread.create
Supported options:
- env
object
Custom environment to bind to the isolated thread scope - require
string|array|object
Source path scripts to load or map of values/functions to bind - namespace
string
Global namespace to allocate the scope environment. Default toenv
- evalPath
string
Path toeval.js
script, required in IE 10 & 11. Default tolib/eval.js
- silent
boolean
Enable/disable silent mode. If enabled, Worker errors will not throw an exception and you should subscribe to theerror
event to handle them properly. Defaultfalse
thread#run(fn, env, args)
Return: task
Alias: exec
Run the given function in the thread isolated scope.
You can optionally bind a custom context (as map
of values) or passing function arguments
(as array
) to be injected when the function will be invoked
Bind values must be serializable types (see threads limitations)
Run a function and return the result synchronously (return
statement required)
Binding a custom context and return the result asynchronously
Passing arguments and return the result asynchronously
thread#pool(number)
Return: thread
Create a pool of a maximum number of threads and run tasks across them
It implements a simple best availability scheudle algorithm to transparently distribute tasks across multiple workers. It will only create a new thread if it's required and there is not any other thread available
This feature is still beta and major improvements will be done in future releases. Any feedback will be really appreciated
// create a pool with a maximum of 10 threadsvar pool = var count = 1var tasks = 50 { } for var i = 0; i < tasks; i += 1
thread#bind(obj)
Return: thread
Alias: set
Bind a map of values to the isolated thread scope.
You can do the same passing an object via thread#require()
Passed values will be exposed in the global namespace (default to env
)
var task = task
thread#require(sources)
Return: thread
Alias: import
Load remote scripts from a valid URL, bind an object or functions to the thread isolated scope.
Passed values will be exposed in the global namespace (default to env
)
Importing a remote script
Or multiple scripts
Binding custom objects and primitives types (does the same as bind()
)
Binding functions
Bind values will be available in the global namespace object (default to env
)
thread#flush()
Return: thread
Flush the thread cached memory and scope environment.
var worker = console // -> 1workerconsole // -> 0
thread#flushTasks()
Return: thread
Flush running tasks promises and clean cached values
var worker = workerconsole // -> 1workerconsole // -> 0
thread#send(msg)
Return: thread
Send a message directly to the current thread.
Useful for specific use cases, but it's preferably do not use it directly.
Use the run()
abstraction instead
Be aware about passing non-serialize data types such as native JavaScript objects, DOM nodes, objects with self-references... (see threads limitations)
var worker = worker
thread#kill()
Return: thread
Alias: terminate
Kill the current thread. All the cached data, scope environment and config options will be flushed, including in worker isolated scope
It's recommended you explicit kill any unused thread in order to avoid memory issues in long term computations
var worker = worker
thread#start([options])
Return: thread
Start (or restart) the current thread. If the thread was previously killed, you can reuse it calling this method
var options = env: x: 2 var worker = worker // explicit killworkerstartoptions // explicit re-start, passing the same options
thread#pending()
Return: number
Return the pending running tasks on the current thread
var worker = var task = workerworker // -> 1task
thread#running()
Return: boolean
Return true
if the current thread has running tasks
// -> true // -> false
thread#idle()
Return: boolean
Alias: sleeping
Return true
if the current thread is in idle state.
A thread will be considered in idle state if its latest executed task exceeds from the idleTime. By default, the idle time will be 30 seconds
var worker = workeridleTime = 1000 // set max 1 secondvar task = worker
thread#terminated
Type: boolean
Expose the thread run state
terminated // -> falseterminated // -> true
thread#on(type, handler)
Return: thread
Alias: addEventListener
Add a custom worker event handler. By default you don't need to handle events directly, use it only for exceptional specific purposes
Supported event are:
- error
- message
thread#off(type, handler)
Return: thread
Alias: removeEventListener
Remove a worker event listener. It's required to pass the original handler function in order to remove it
thread#maxTaskDelay
Type: number
Default: 0
The maximum amount of time that a task can take in miliseconds. If the task computation time exceed, it will be exit as error.
By default this feature is disabled in order to avoid unnecessary computations
This value will be applied to every task which runs in the current thread or a pool of threads
var worker = workermaxTaskDelay = 1000worker
thread#idleTime
Type: number
Default: 30000
The minimum time in milliseconds that a thread is considered in sleeping (idle) state
thread#isPool
Type: boolean
Check if the current thread
instance is a pool of threads
var pool = poolisPool // -> true
thread.Task(thread [, env])
Return: task
Create a new task in the given thread
Normally you don't need to call it directly, it will done via thread.run()
factory
var worker = var task = worker y: 2 task
Task#then(successFn [, errorFn])
Return: task
Alias: success
Add success and error (optionally) result handlers for the current task
var worker = vas task = workertask
Task#catch(errorFn)
Return: task
Alias: error
Add an error handlers for the current task
var worker = vas task = workertask
Task#finally(finalFn)
Return: task
Alias: finish
Add a final handler for the current task.
It will be ejecuted when the task finished with success
or error
state
var worker = vas task = workertask
Task#bind(obj)
Return: task
Bind custom map environment to the current task scope
var worker = vas task = workertasktask
Task#flush()
Return: task
Flush cached result data and set the initial task state
var worker = vas task = workertasktask // -> true
Task#flushed()
Return: boolean
Return true
if task data was already flushed
Static members
thread.all()
Return: array
Return an array of created threads (running and idle)
thread.total()
Return: number
Return the total number of created threads (running and idle)
thread.all()
Return: array
Return an array with all created threads
thread.running()
Return: array
Return an array
of the running threads (are processing one or more tasks)
thread.idle()
Return: array
Return an array
of the idle threads (thread which has no execute tasks for a long time)
thread.killAll()
Alias: terminateAll
Kill all the created threads (under active
or idle
state)
thread.killIdle()
Alias: terminateIdle
Kill all the threads under idle
state
thread.flush()
Flush the built-in threads store manager (but they will not be killed)
thread.VERSION
Type: string
Current library semantic version
Contributing
Wanna help? Cool! It will be appreciated :)
You must add new test cases for any new feature or refactor you do, always following the same design/code patterns that already exist
Development
Only node.js is required for development
Clone the repository
$ git clone https://github.com/h2non/thread.js.git && cd thread.js
Install dependencies
$ npm install
Generate browser bundle source
$ make browser
Run tests
$ make test
See the examples
$ ./node_modules/.bin/http-server
License
MIT © Tomas Aparicio