Generators + promises = taskjs
Task.js is an experimental library for ES6 that makes sequential, blocking I/O simple and beautiful, using the power of JavaScript’s new yield operator.
Tasks are interleaved like threads, but they are cooperative rather than pre-emptive: they block on promises with yield. Here’s an example using jQuery :
Quick Start
The power of task.js comes from ES6 generators, which are currently only available in Firefox. You can try it out in Firefox, although there are a few remaining incompatibilities with the current ES6 spec (which is still a work in progress).
Here’s a “hello world” of tasks that will work in Firefox:
The spawn function takes a generator function and starts running it as a concurrently-executed task. Every time the task yields a promise, the scheduler blocks the task until the promise is fulfilled.
Tasks
function spawn( f ) → Task
Creates a new task and automatically starts it.
f() → generator
A function to produce the generator for running the task. The function is called with this bound to the new task.
class Task< A > is promise< A >
A concurrent and suspendable computation.
[new] Task( f )
f() → generator
A function to produce the generator for running the task. The function is called with this bound to the new task.
Task.current() → Task | null
Returns the currently executing task, if any.
t.start() → t
Starts the task. If the task is blocked on a promise, the task will not resume executing until the promise is fulfilled. Otherwise, the scheduler will resume the task at some point.
t.pause() → t
Pauses the task. Even when the task is ready to resume, it will not resume until it is started again. If the task is waiting on a promise that becomes fulfilled while the task is paused, its result will not be lost; it will be returned whenever the task is started again.
A task cannot be paused if it is currently running. To pause a running task after it reaches its next yield-point, enqueue a callback to pause it in a different turn of the event loop:
t.isStarted() → boolean
Indicates whether the task is started.
t.isRunning() → boolean
Indicates whether the task is currently executing.
inherits from Promise< A >
get, put, call, addCallback, addErrback, addBoth, addCallbacks, timeout
interface generator
An object encapsulating a suspendable computation. In ES6, generators can be conveniently created using the yield operator.
g.send( result ) → promise< any > | falsey
Resumes the computation to its next yield point or completion, whichever comes first. The computation should yield either a promise, indicating that the computation is blocked until the promise is fulfilled, or a falsey value, indicating that the computation is immediately ready to resume.
result : any
The result to resume the previous yield with.
g.throw( error ) → promise< any > | falsey
Resumes the computation by throwing an error. The computation runs to its next yield point or completion, whichever comes first. The computation should yield either a promise, indicating that the computation is blocked until the promise is fulfilled, or a falsey value, indicating that the computation is immediately ready to resume.
error : any
The error to throw in the resumed computation.
g.close() → any
Cancels the computation, executing any live finally blocks remaining in the generator. Closing the computation should not expect to be able to return any more promises; they will be ignored by the scheduler, which will consider the computation to be terminated.
class TaskResult< A >
ES6 allows generator functions to return a value, but the Firefox JavaScript engine (the only that currently implements generators) does not yet allow this. To produce a result value from a task, throw an instance of this class.
r.value : A
The task result value.
Promises
interface promise< A >
An object representing an “eventual value,” i.e., a value that may not be ready yet but will be provided at some point in the future.
p.then( [ onResolve [, onError [, onProgress ] ] ] ) → promise< B >
Registers callbacks to be called by the promise.
onResolve( result ) → B
Callback to be called by the promise when it produces its result.
result : A The result value produced by the promise.
onError( error ) → B
Callback to be called by the promise when it throws an error while trying to produce its result.
error : any The error thrown while attempting to produce a result.
onProgress() → any
Callback to be called by the promise while making progress towards producing its result.
p.cancel() → any
Cancel the retrieval of the promise’s value. If the promise is already fulfilled, this operation does nothing.
function now( value ) → promise< A >
Converts an ordinary value into a fulfilled promise.
value : any
The promise’s resolved value.
function never() → promise< any >
Produces a promise that is never fulfilled.
function join( promise … ) → promise< [A] >
Produces a promise that is resolved when all the given promises are resolved. The resolved value is an array of each of the resolved values of the given promises.
If any of the promises is rejected, the joined promise is rejected with the same error, and any remaining unfulfilled promises are cancelled.
promise : promise< A >
A promise to join.
function choose( promise … ) → promise< A >
Produces a promise that is fulfilled when any one of the given promises is fulfilled. As soon as one of the promises is fulfilled, whether by being resolved or rejected, all the other promises are cancelled.
promise : promise< A >
A promise to choose from.
function sleep( delay[, compensate=false ] ) → promise< uint32 >
Produces a promise that is resolved when a given amount of time elapses, using the builtin global setTimeout function.
The promise’s resolved value is the actual number of milliseconds elapsed since the promise was created.
delay : uint32
The number of milliseconds to sleep for.
compensate : boolish
Indicates whether to compensate for imprecision in the host platform by continuing to sleep if the timeout completes before the indicated number of milliseconds have elapsed.
Scheduling
interface scheduler
An object providing a scheduling policy. A scheduler maintains an internal collection of scheduled tasks and decides which task to choose next for execution.
s.choose() → Task
Chooses a scheduled task for the runtime to execute next, removing it from the internal collection of scheduled tasks.
s.schedule( task ) → any
Adds a task to the scheduler’s internal collection of scheduled tasks. The task is guaranteed not to be currently scheduled.
task : Task
The task to schedule.
s.unschedule( task ) → any
Removes a task from the scheduler’s internal collection of scheduled tasks. The task may or may not already be scheduled.
task : Task
The task to unschedule.
function currentScheduler() → scheduler
Returns the currently-installed system scheduler.
function setCurrentScheduler( scheduler ) → void
Installs a new system scheduler. Any existing tasks will continue to be scheduled via the scheduler they were created with, but new tasks will be associated with the new scheduler.
scheduler : scheduler
The new scheduler.
class RandomScheduler is scheduler
A scheduler that chooses tasks randomly using Math.random.
function enqueue( f ) → void
Calls the given function in a separate turn of the event loop.
f() → any
The function to call in another event loop turn.
Internal
class Deferred< A > is promise< A >
A low-level promise that can be manually fulfilled.
[new] Deferred( [ cancel ] )
d.resolve( result ) → void
d.reject( error ) → void
inherits from Promise< A >
get, put, call, addCallback, addErrback, addBoth, addCallbacks, timeout
class Promise< A >
A partial implementation of a promise, providing utility methods common in popular promise implementations. To implement the full promise API, instances must be given then and cancel methods.
[new] Promise()
p.get( key )
p.put( key, val )
p.call( key, …args )
p.addCallback( callback )
p.addErrback( errback )
p.addBoth( callback )
p.addCallbacks( callback, errback )
p.timeout( delay [, compensate=false ] )