asyncbox
A collection of ES7 async/await utilities. Install via NPM:
npm install asyncbox
Then, behold!
Sleep
An async/await version of setTimeout
import { sleep } from 'asyncbox';
async function myFn () {
await sleep(1000);
};
Long Sleep
Sometimes Promise.delay
or setTimeout
are inaccurate for large wait times. To safely wait for these long times (e.g. in the 5+ minute range), you can use longSleep
:
import { longSleep } from 'asyncbox';
async function myFn () {
await longSleep(10 * 60 * 1000);
await longSleep(5000, {thresholdMs: 10000});
await longSleep(5000, {intervalMs: 500});
}
You can also pass a progressCb
option which is a callback function that receives an object with the properties elapsedMs
, timeLeft
, and progress
. This will be called on every wait interval so you can do your wait logging or whatever.
function progressCb({elapsedMs, timeLeft, progress}) {
console.log(`We are {progress * 100}% complete waiting`);
}
await longSleep(10 * 60 * 1000, {progressCb});
Retry
An async/await way of running a method until it doesn't throw an error
import { sleep, retry } from 'asyncbox';
async function flakeyFunction (val1, val2) {
if (val1 < 10) {
throw new Error("this is a flakey value");
}
await sleep(1000);
return val1 + val2;
}
async function myFn () {
let randVals = [Math.random() * 100, Math.random() * 100];
let randSum = await retry(3, flakeyFunction, ...randVals);
}
You can also use retryInterval
to add a sleep in between retries. This can be
useful if you want to throttle how fast we retry:
await retryInterval(3, 1500, expensiveFunction, ...args);
Filter/Map
Filter and map are pretty handy concepts, and now you can write filter and map
functions that execute asynchronously!
import { asyncmap, asyncfilter } from 'asyncbox';
Then in your async functions, you can do:
const items = [1, 2, 3, 4];
const slowSquare = async (n) => { await sleep(5); return n * 2; };
let newItems = await asyncmap(items, async (i) => { return await slowSquare(i); });
console.log(newItems);
const slowEven = async (n) => { await sleep(5); return n % 2 === 0; };
newItems = await asyncfilter(items, async (i) => { return await slowEven(i); });
console.log(newItems);
By default, asyncmap
and asyncfilter
run their operations in parallel; you
can pass false
as a third argument to make sure it happens serially.
Nodeify
Export async functions (Promises) and import this with your ES5 code to use it
with Node.
var asyncbox = require('asyncbox')
, sleep = asyncbox.sleep
, nodeify = asyncbox.nodeify;
nodeify(sleep(1000), function (err, timer) {
console.log(err);
console.log(timer);
});
nodeifyAll
If you have a whole library you want to export nodeified versions of, it's pretty easy:
import { nodeifyAll } from 'asyncbox';
async function foo () { ... }
async function bar () { ... }
let cb = nodeifyAll({foo, bar});
export { foo, bar, cb };
Then in my ES5 script I can do:
var myLib = require('mylib').cb;
myLib.foo(function (err) { ... });
myLib.bar(function (err) { ... });
waitForCondition
Takes a condition (a function returning a boolean or boolean promise),
and waits until the condition is true.
Throws a /Condition unmet/
error if the condition has not been
satisfied within the allocated time, unless an error is provided in
the options, as the error
property, which is either thrown itself, or
used as the message.
The condition result is returned if it is not falsy. If the condition
throws an error then this exception will be immediately passed through.
The default options are: { waitMs: 5000, intervalMs: 500 }
function condFn () { return Math.random()*1000 > 995; }
await waitForCondition(condFn);
await waitForCondition(condFn, {
waitMs: 300000,
intervalMs: 10000
});
await waitForCondition(condFn, {
waitMs: 300000,
intervalMs: 10000
logger: myLogger
});
try {
await waitForCondition(condFn, {
error: 'Unable to satisfy condition'
});
} catch (err) {
}
const error = new Error('Unable to satisfy condition');
try {
await waitForCondition(condFn, {
error: error
});
} catch (err) {
}
Run the tests
npm test