async-patterns
v3.0.2
Published
A a collection of design patterns for async/await or promise-driven async code
Downloads
29
Readme
async-patterns
async-patterns
is a collection of design patterns for async/await or promise-driven async code. The design patterns in this library are constructors that build callback-expecting functions. Each pattern is designed to be a stand-alone piece of code, tested for performance and robustness.
API
async-patterns : object
A namespace.
Kind: global namespace
- async-patterns : object
- .Callbackify ⇒ function
- .CatchError ⇒ function
- .InOrder ⇒ function
- .InParallel ⇒ function
- .InSeries ⇒ function
- .LogError ⇒ function
- .ParallelFilter ⇒ function
- .ParallelMap ⇒ function
- .PassThrough
- .Promisify ⇒ function
- .Race ⇒ function
- .testing : object
- .AssertionTest
- new AssertionTest()
- assertionTest.describe(description) ⇒ AssertionTest
- assertionTest.setup(task) ⇒ AssertionTest
- assertionTest.prepare(task) ⇒ AssertionTest
- assertionTest.execute(task) ⇒ AssertionTest
- assertionTest.verify(...tasks) ⇒ AssertionTest
- assertionTest.teardown(task) ⇒ AssertionTest
- assertionTest.build() ⇒ function
- AssertionTest.VerifyErrorWasNotThrown()
- AssertionTest.VerifyErrorWasNotThrown()
- .AssertionTest
- .unstable : object
- .TraceError(task) ⇒ function
- .Assert(validator, message) ⇒ taskFunction
- .Delay(delay) ⇒ taskFunction
- .If(ifTask, thenTask, elseTask) ⇒ taskFunction
- .Logging(...statements) ⇒ taskFunction
- .Memoize(task, [keyFunction]) ⇒ AsyncTask
- .Retry(task, options) ⇒ taskFunction
- .Throttle(task, limit) ⇒ taskFunction
- .TimeIn(task, ms) ⇒ taskFunction
- .TimeOut(task, ms) ⇒ taskFunction
- .Timer(task, label) ⇒ taskFunction
- .While(conditionTask, loopTask) ⇒ function
async-patterns.Callbackify ⇒ function
const task = Callbackify(
async (i) => i + 1
);
// logs 'res 1', eventually
task(
(err, res) => console.log('res', res),
0
);
Kind: static property of async-patterns
Returns: function - a callback-expecting function
Params
- task function - an async function
async-patterns.CatchError ⇒ function
let task = CatchError(task);
const { error, result } = await task(request);
Kind: static property of async-patterns
Returns: function - an async wrapper function around the task
Params
- task function - an async function to wrap around with a catch wrapper.
async-patterns.InOrder ⇒ function
let InOrder = require('async-patterns/InOrder');
const task = InOrder(
async (i) => i + 1,
async (i) => i + 1,
async (i) => i + 1
);
await task(0); // returns 3
Kind: static property of async-patterns
Returns: function - an async wrapper function that runs all of the tasks in order, calling each one with original request
Params
- ...tasks function - any number of async tasks.
async-patterns.InParallel ⇒ function
let InParallel = require('async-patterns/InParallel');
const task = InParallel(
async (i) => i + 1,
async (i) => i + 2,
async (i) => i + 3
);
const results = await task(0); // results is [1, 2, 3]
Kind: static property of async-patterns
Returns: function - an async wrapper function that runs all the tasks in parallel, and returns an array of results
Params
- ...tasks function - any number of async tasks.
async-patterns.InSeries ⇒ function
let InSeries = require('async-patterns/InSeries');
const task = InSeries(
async (i) => i + 1,
async (i) => i + 1,
async (i) => i + 1
);
const results = await task(0); // results is 3
Kind: static property of async-patterns
Returns: function - an async wrapper function that runs all of the tasks in series, calling each one with the results of the previous one
Params
- ...tasks function - any number of async tasks.
async-patterns.LogError ⇒ function
let task = LogError(task);
// if an error occurs, it will be logged before getting re-thrown here
const result = await task(request);
Kind: static property of async-patterns
Returns: function - an async wrapper function around the task
Params
- task function - an async function to wrap around with a error logging wrapper.
async-patterns.ParallelFilter ⇒ function
const task = ParallelFilter(
async (val, i) => val % 2 === 0
);
const results = await task([0, 1, 2]); // results is [0, 2]
Kind: static property of async-patterns
Returns: function - an async wrapper function that takes in an array of requests, runs the task in parallel, once for each input in the array, and returns an array of results
Params
- task function - the filtering task
async-patterns.ParallelMap ⇒ function
const task = ParallelMap(
async (val, i) => val + 1
);
const results = await task([0, 1, 2]); // results is [1, 2, 3]
Kind: static property of async-patterns
Returns: function - an async wrapper function that takes in an array of requests, runs the task in parallel, once for each input in the array, and returns an array of results
Params
- task function - the mapping task
async-patterns.PassThrough
const task = PassThrough;
const results = await task(0); // results is 0
PassThrough does nothing, just passes the request through as the result
Kind: static property of async-patterns
async-patterns.Promisify ⇒ function
const task = Promisify(
(onDone, i) => onDone(
i === 0 ? new Error('i cant be 0') : null,
i + 1
),
);
const results = await task(1); // results is 2
const results2 = await taks(0); // throws 'i cant be 0 Error
Kind: static property of async-patterns
Returns: function - an async function
Params
- task function - a callback-expecting function
async-patterns.Race ⇒ function
const task = Race(
async (i) => i + 1,
async (i) => i + 2,
);
const result = await task(1); // 2
Kind: static property of async-patterns
Returns: function - an async task that resolves or rejects as soon as the first one of its "children" resolves or rejects
Params
- ...tasks function - any number of async tasks
async-patterns.testing : object
A namespace.
Kind: static namespace of async-patterns
- .testing : object
- .AssertionTest
- new AssertionTest()
- assertionTest.describe(description) ⇒ AssertionTest
- assertionTest.setup(task) ⇒ AssertionTest
- assertionTest.prepare(task) ⇒ AssertionTest
- assertionTest.execute(task) ⇒ AssertionTest
- assertionTest.verify(...tasks) ⇒ AssertionTest
- assertionTest.teardown(task) ⇒ AssertionTest
- assertionTest.build() ⇒ function
- AssertionTest.VerifyErrorWasNotThrown()
- AssertionTest.VerifyErrorWasNotThrown()
- .AssertionTest
testing.AssertionTest
Kind: static class of testing
- .AssertionTest
- new AssertionTest()
- assertionTest.describe(description) ⇒ AssertionTest
- assertionTest.setup(task) ⇒ AssertionTest
- assertionTest.prepare(task) ⇒ AssertionTest
- assertionTest.execute(task) ⇒ AssertionTest
- assertionTest.verify(...tasks) ⇒ AssertionTest
- assertionTest.teardown(task) ⇒ AssertionTest
- assertionTest.build() ⇒ function
- AssertionTest.VerifyErrorWasNotThrown()
- AssertionTest.VerifyErrorWasNotThrown()
new AssertionTest()
const PingTest = AssertionTest()
.describe('can ping internet')
.setup(
// build our setup
(next) => {
const setup = {};
setup.testHosts = [ 'google.com', 'microsoft.com', 'yahoo.com' ];
next(null, setup);
}
)
.prepare(
// run test with first host
(next, setup) => {
const host = setup.testHosts[0];
next(null, host);
}
)
.execute(
(next, host) => ping.sys.probe(
host,
(isAlive, error) => next(error, isAlive)
)
)
.verify(
// verify no error was thrown
(next, { setup, request, result, error }) => next(error),
// verify result is true
(next, { setup, request, result, error }) => next(
result !== true ? new Error(`could not ping host ${request}`) : null
)
)
.teardown(
// nothing to teardown
(next, { setup, request, result, error }) => next()
)
.build();
test( () => console.log('test done') );
Constructor for an AssertionTest builder.
assertionTest.describe(description) ⇒ AssertionTest
AssertionTest#describe
lets you set a description for a test case.
This description is part of the label attached to the test case when built.
Kind: instance method of AssertionTest
Returns: AssertionTest - this
Params
- description string - a string label describing the test case
assertionTest.setup(task) ⇒ AssertionTest
AssertionTest#setup
gives you a hook to build test fixtures before execution.
This is the first step that runs in a test.
setup
is a separate step from prepare
because you often want to use
a common setup function to build test fixtures for multiple tests.
Kind: instance method of AssertionTest
Returns: AssertionTest - this
Params
- task function - a setup task function - should return a setup object
assertionTest.prepare(task) ⇒ AssertionTest
AssertionTest#prepare
gives you a hook to prepare the request that the test uses to execute.
This is the second step that runs in a test, and the last step before execute
.
The prepare
task is passed the results from setup
.
Kind: instance method of AssertionTest
Returns: AssertionTest - this
Params
- task function - a prepare task function - should accept a context containing the setup, and return a request object to be given to the executing task
assertionTest.execute(task) ⇒ AssertionTest
AssertionTest#execute
lets you specify the task that is executed in a test.
The execute
task is passed the results from prepare
.
Kind: instance method of AssertionTest
Returns: AssertionTest - this
Params
- task function - the task the test should execute, and capture results and errors from
assertionTest.verify(...tasks) ⇒ AssertionTest
AssertionTest#verify
lets you specify any number of tasks to verify the test results.
Each verify
task is passed a complete record of all test fixtures in an object,
including the setup, the request, the result, and the error (if an error was thrown)
Kind: instance method of AssertionTest
Returns: AssertionTest - this
Params
- ...tasks function - any number of verification tasks
assertionTest.teardown(task) ⇒ AssertionTest
AssertionTest#teardown
gives you a hook to tear down the test fixtures after execution.
The teardown
task is passed a complete record of all test fixtures in an object,
including the setup, the request, the result, and the error (if an error was thrown)
Kind: instance method of AssertionTest
Returns: AssertionTest - this
Params
- task function - a task to tear down the setup
assertionTest.build() ⇒ function
Builds the test case function.
Kind: instance method of AssertionTest
Returns: function - callback-expecting test function
AssertionTest.VerifyErrorWasNotThrown()
verifier function to make sure test DID NOT throw an error
Kind: static method of AssertionTest
AssertionTest.VerifyErrorWasNotThrown()
verifier function to make sure test DID throw an error
Kind: static method of AssertionTest
async-patterns.unstable : object
A namespace.
Kind: static namespace of async-patterns
unstable.TraceError(task) ⇒ function
TraceError is an experimental wrapper that attempts to make errors more informative. It does this by appending extra information to the stack of any error thrown in the task.
NOTE: TraceError is marked as 'unstable' as stack traces in JS are not standardized, so it may not always provide useful information.
Kind: static method of unstable
Returns: function - a wrapper function that modifies the stack trace of any errors thrown within
Params
- task function - a task function to wrap
async-patterns.Assert(validator, message) ⇒ taskFunction
let Assert = require('async-patterns/Assert');
let InSeries = require('async-patterns/InSeries');
let task = InSeries(
(num) => num,
Assert(
(num) => (num >= 0),
(num) => `${num} is less than zero`
),
(num) => num,
);
await task(1); // returns 1
await task(-1); // throws error
Builds an async assertion task.
Kind: static method of async-patterns
Returns: taskFunction - an assertion task
Params
- validator function - a function that checks the arguments.
- message string - an optional error message to throw if the assertion fails, or a message builder function.
async-patterns.Delay(delay) ⇒ taskFunction
let Delay = require('async-patterns/Delay');
let InSeries = require('async-patterns/InSeries');
let task = InSeries(
(num) => num + 1
Delay(100),
);
await task(1); // returns 2, after a 100ms delay
Delay acts like PassThrough, but inserts a delay in the call.
Kind: static method of async-patterns
Returns: taskFunction - a delay task
Params
- delay number - The time to delay, in ms.
async-patterns.If(ifTask, thenTask, elseTask) ⇒ taskFunction
let If = require('async-patterns/If');
let logIfEven = If(
(num) => (num % 2 === 0),
(num) => { console.log('is even!'); },
(num) => { console.log('is not even!'); }
);
await logIfEven(1); // prints out 'is not even!' eventually
await logIfEven(2); // prints out 'is even!' eventually
If accepts up to three tasks, an 'if' task, a 'then' task, and lastly an 'else' task note: by default, the ifTask, thenTask, and elseTask are PassThrough note: the ifTask can return multiple results, but only the first is checked for truthiness
Kind: static method of async-patterns
Params
- ifTask taskFunction - a condition task.
- thenTask taskFunction - a task to run when ifTask returns a truthy value.
- elseTask taskFunction - a task to run when ifTask returns a falsy value.
async-patterns.Logging(...statements) ⇒ taskFunction
A logging utility. It passes the arguments received into all the statements, collects the results, and joins them together with newlines to build the final log statement
Kind: static method of async-patterns
Returns: taskFunction - a logging task
Params
- ...statements function - any number of logging values. Functions are called with the calling arguments, everything else is passed directly to
async-patterns.Memoize(task, [keyFunction]) ⇒ AsyncTask
Memoize builds a wrapper function that caches results of previous executions. As a result, repeated calls to Memoize may be much faster, if the request hits the cache.
NOTE: As of now, there are no cache eviction mechanisms. You should try to use Memoized functions in a 'disposable' way as a result
NOTE: Memoize is not 'thread-safe' currently. If two calls are made for the same object currently, two calls to the wrapped function will be made
NOTE: Memoize will cache errors as well as results.
Kind: static method of async-patterns
Params
- task AsyncTask - the task function to memoize.
- [keyFunction] function - a function that synchronously generates a key for a request.
async-patterns.Retry(task, options) ⇒ taskFunction
Wraps a task and attempts to retry if it throws an error, with an exponential backoff.
Kind: static method of async-patterns
Returns: taskFunction - a task
Params
- task taskFunction - the task to wrap.
- options object - an optional set of retry options.
- .timeout object - maximum time to attempt retries.
- .retries object - maximum number of retries to attempt.
async-patterns.Throttle(task, limit) ⇒ taskFunction
Wraps a task and ensures that only X number of instances of the task can be run in parallel. Requests are queued up in an unbounded FIFO queue until they can be run.
Kind: static method of async-patterns
Returns: taskFunction - a task
Params
- task taskFunction - the task to throttle
- limit number - the number of instances that can run in parallel. default 1.
async-patterns.TimeIn(task, ms) ⇒ taskFunction
let TimeIn = require('async-patterns/TimeIn');
let task = TimeIn(
async function (...args) {},
1000
);
await task(...args);
TimeIn wraps a single task function, and returns a function that only returns after X ms.
Kind: static method of async-patterns
Returns: taskFunction - a task
Params
- task taskFunction - the task to wrap in a timeout.
- ms number - the timein in ms.
async-patterns.TimeOut(task, ms) ⇒ taskFunction
let TimeOut = require('async-patterns/TimeOut');
let task = TimeOut(
async function (...args) {},
1000
);
await task(...args);
TimeOut wraps a single task function, and returns a function that returns early if the task fails to complete before the timeout triggers.
NOTE: the timeout being triggered will not cancel the original task.
Kind: static method of async-patterns
Returns: taskFunction - a task
Params
- task taskFunction - the task to wrap in a timeout.
- ms number - the timeout in ms.
async-patterns.Timer(task, label) ⇒ taskFunction
Wraps a task and logs how long it takes to finish, or fail.
Kind: static method of async-patterns
Returns: taskFunction - a task
Params
- task taskFunction - the task to wrap.
- label string - an optional label to log.
async-patterns.While(conditionTask, loopTask) ⇒ function
let While = require('async-patterns/While');
let task = While(
(num) => (num < 10),
(num) => num + 1
);
await task(1); // prints 10, eventually
While accepts two tasks and returns a task that conditionally executes some number of times.
Kind: static method of async-patterns
Params
- conditionTask function - a condition task.
- loopTask function - a task to run if the condition returns a truthy value.