Promist

A dependable promises and async utility belt. Not a Promise
implementation.
Install
npm install promist
Basics
Promist intends to cover and abstract the most common day to day dealings with async behavior and promises. It doesn't intend to be the most complete library, or an incredibly slim one, but rather be a dependable set of functions that serve as go-to for most use cases.
Promises
Create functions
Create functions return a new promise.
wait(ms: number): Promise
Returns a promise that will resolve after ms
milliseconds;
ms
: Number of milliseconds to wait for until resolution.
import { wait } from 'promist';
wait(100).then(() => console.log('Resolved after 100ms'));
waitUntil(test: Function, ms?: number): Promise
Returns a promise that resolves when test
returns truthy, with its value.
test
: Test function, with signature () => boolean | Promise<boolean>
.ms
: The frequency test
should be called at until it returns truthy. Default: 20
.
import { waitUntil } from 'promist';
let example = 1;
waitUntil(() => example === 10)
.then(() => console.log('Resolved after example = 10'));
example = 10;
deferred(): Promise
Returns a newly formed deferrable promise, with methods:
promise.resolve(value: any): void
: Resolves the promise.promise.reject(reason: any): void
: Rejects the promise.
import { deferred } from 'promist';
const promise = deferred();
promise.then(value => console.log(`Resolves with "Hello": ${value}`));
promise.resolve('Hello');
lazy(executor: Function): Promise
Returns a lazy promise: it's executor won't run until promise.then()
, promise.catch()
, or promise.finally()
are called for the first time.
import { lazy } from 'promist';
const promise = lazy((resolve, reject) => {
const value = 1 + 1;
resolve(value);
});
promise.then((value) => console.log(`Executor has run and resolved: ${value}`));
lazy.fn(fn: Function): Promise
Instead of taking an executor
, lazy.fn
takes a promise returning function that won't be executed until promise.then()
, promise.catch()
, or promise.finally()
are called for the first time.
import { lazy } from 'promist';
const promise = lazy.fn(() => Promise.resolve(10));
promise.then((value) => console.log(`Function has run and resolved: ${value}`));
Extend functions
Extend functions return a new instance extending an input promise:
- They can be chained via
pipe
. - They might not work adequately if you're using non-standard methods for resolution other than
promise.then()
, promise.catch()
, or promise.finally()
.
deferrable(promise: Promise): Promise
promise
will acquire:
promise.resolve(value: any)
: Resolves the promise with the given value
.promise.reject(reason: any)
: Rejects the promise with the given reason
.
If the input promise
resolves or rejects before promise.resolve()
or promise.reject()
are called, they won't have any effect. If the opposite occurs, the resolution or rejection value of the input promise will be discarded.
import { wait, deferrable } from 'promist';
const foo = deferrable(wait(100).then(() => 'Value 1'));
foo.resolve('Value 2');
foo.then((value) => console.log(`It will resolve with "Value 2": ${value}`));
const bar = deferrable(Promise.resolve('Value 1'));
wait(100).then(() => bar.resolve('Value 2'));
bar.then((value) => console.log(`It will resolve with "Value 1": ${value}`));
cancellable(promise: Promise): Promise
promise
will acquire:
promise.cancel()
: Cancels the promise.promise.cancelled
: boolean, whether or not the promise has been cancelled.
import { cancellable } from 'promist';
const extended = cancellable(promise);
extended.cancel();
stateful(promise: Promise): Promise
promise
will acquire:
promise.status
: string, either "pending"
, "resolved"
, or "rejected"
.promise.value
: Contains the resolution value. null
if the promise is pending or rejected.promise.reason
: Contains the rejection reason. null
if the promise is pending or resolved.
import { stateful } from 'promist';
const extended = stateful(promise);
timed(promise: Promise): Promise
promise
will acquire:
promise.time
: number | void, the number of milliseconds it took the promise to resolve or reject. Defaults to null
before it's resolved/rejected. The count starts the moment timed()
is called.
import { timed } from 'promist';
const extended = timed(promise);
delay(ms: number, delayRejection?: boolean): Function
ms
: Threshold in milliseconds.delayRejection
: Whether or not to also delay a promise rejection. Default: false
.
Returns a function with signature: (promise: Promise) => Promise
.
The returned promise will acquire a lower threshold in ms
for promise resolution. If the original promise
resolves before ms
, the returned promise won't resolve until ms
have passed; if it resolves after, it will resolve immediately. The count starts the moment delay()()
is called.
import { delay } from 'promist';
const extended = delay(500)(promise);
extended.then(() => {
})
timeout(ms: number, reason?: boolean | Error): Function
ms
: Threshold in milliseconds.reason
: Value the promise will reject with if it doesn't fulfill in ms
milliseconds:
- If
undefined
or false
, the promise will cancel (never resolve) instead of rejecting. - If
true
, it will reject with a default error. - If an Error instance, it will reject with it.
Returns a function with signature: (promise: Promise) => Promise
.
The returned promise will acquire an upper threshold in ms
after which, if it hasn't fulfilled, it will either cancel or reject, depending on whether a reason
argument was passed. The count starts the moment timeout()()
is called.
import { timeout } from 'promist';
const foo = timeout(500)(promise);
const bar = timeout(500, true)(promise)
Utils
clone(promise: Promise): Promise
Clones a Promise or Promist extended Promise, returning a new instance with the same extensions. Cloning is already done by default when using any extend function on a Promise.
promise
: A standard Promise or Promist extended Promise.
import { clone, deferrable } from 'promist';
const source = deferrable(Promise.resolve());
const promise = clone(source);
promise.resolve('foo');
pipe(...fns: Function[]): Function
Takes in a number of extend functions as arguments, and returns a function with signature: (promise: Promise): Promise
.
import { pipe, cancellable, delay, deferrrable } from 'promist';
const promise = pipe(delay(500), cancellable, deferrable)(source);
control(test: Function, generator: Function): Function
Used to control async flow. It returns a promise returning function taking the same arguments as generator
.
test
: A test function (can be async
) that will be run before calling each next()
on generator
, with signature () => Promise<boolean | Error> | boolean | Error
. It can return:
false
: generator
will not continue execution (it will never resolve).true
: generator
will continue execution until the next yield
.Error
: generator
call will return a rejected promise. The same behavior can be expected if the error is thrown instead of returned.
generator
: must be a generator function. Within it, you'd use yield
as you would await
for an async
function.
import { control } from 'promist';
function* gen(n) {
let res = yield Promise.resolve(n * 2);
res = yield Promise.resolve(res * 5);
return res;
}
const willContinue = control(() => true, gen);
const willNotContinue = control(() => false, gen);
const willReject = control(() => Error('An error ocurred'), gen);
willContinue(1).then(console.log);
willNotContinue(2).then(console.log);
willReject(3).then(console.log).catch(console.error);
isPromise(value: any): boolean
Returns true
if value
is a thenable, false
otherwise.
value
: The object to test.
import { isPromise } from 'promist';
if (isPromise(promise)) {
promise.then(() => { });
}
isPromist(promise: Promise, kind: string): boolean
Returns true
if a Promise is of a particular promist extension kind
.
promise
: The Promise to test.kind
: string, one of 'cancellable'
, 'deferrable'
, 'stateful'
, or 'timed'
.
import { isPromist } from 'promist';
if (isPromist(promise, 'deferrable')) {
promise.resolve('foo');
}
Collections
-
Series:
- Collection functions execute serially.
- The passed functions (callbacks) receive an array of promises.
-
Parallel:
- Collection functions execute in parallel in two stages: first, the resolution of all promises, then the passed function calls.
- The passed functions (callbacks) receive an array with the values the input array of promises resolved to.
parallel.reduce()
receives a promise as the accumulator parameter.
import { parallel } from 'promist';
import { series } from 'promist';
parallel.map(promiseArr, (x, i, arr) => {
return x;
});
series.map(promiseArr, (x, i, arr) => {
return x;
})
map(arr: Promise[], callback: Function): Promise
arr
: An array of promises.callback
: With the same signature as Array.prototype.map()
. Can be a promise returning/async function.
filter(arr: Promise[], callback: Function): Promise
arr
: An array of promises.callback
: With the same signature as Array.prototype.filter()
. Can be a promise returning/async function.
reduce(arr: Promise[], callback: Function, initialValue: any): Promise
arr
: An array of promises.callback
: With the same signature as Array.prototype.reduce()
. Can be a promise returning/async function.initialValue
: An initial value; if absent, the resolved value of the first promise in the array will be taken as initialValue
.
each(arr: Promise[], callback: Function): Promise
arr
: An array of promises.callback
: With the same signature as Array.prototype.forEach()
. Can be a promise returning/async function.