Package Exports
- c-promise2
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (c-promise2) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
Table of contents
- SYNOPSIS
- Why
- Features
- Installation
- Examples:
- Using generators
- Related projects
- API Reference
- License
SYNOPSIS ✨
This library provides an advanced version of the built-in Promise by subclassing. You might be interested in using it if you need the following features:
- promise cancellation (including nested)
- progress capturing
- promise suspending
- timeouts
- concurrent limit for
all
andallSettled
methods withmapper
reducer
In terms of the library the cancellation means rejection with a special error subclass.
const chain= new CPromise((resolve, reject, {onCancel, onPause, onResume})=>{
onCancel(()=>{
//optionally some code here to abort your long-term task (abort request, stop timers etc.)
});
}).then(console.log, console.warn);
setTimeout(()=> chain.cancel(), 1000);
Why ❓
You may face with a challenge when you need to cancel some long-term asynchronous operation before it will be completed with success or failure, just because the result has lost its relevance to you.
Features
- no dependencies (except [native] Promise)
- built-in
AbortController
class - browser support
- supports two ways to make your promise internal code cancellable:
onCancel
callbacks (clear timers, abort requests)signal
provided by the AbortController (to wrap API like fetch method)
- 🔥 supports cancellation of the whole chain
- 🔥 supports generator to CPromise resolving (something similar like co library does);
- 🔥 progress capturing support
CPromise.all
supports concurrency limitCPromise.all
andCPromise.race
methods have cancellation support, so the others nested pending promises will be canceled when the result promise settled- promise suspending (using
pause
andresume
methods) - custom signals (
emitSignal
) delay
method to return promise that will be resolved with the value after timeout- ability to set the
weight
for each promise in the chain to manage the impact on chain progress - ability to attach meta info on each setting of the progress
catch
method supports error class filtering
Installation 🔨
- Install for node.js using npm/yarn:
$ npm install c-promise2
$ yarn add c-promise2
The package consists pre-built bundles for umd, cjs, mjs versions which can be found in the ./dist/
directory
- Import the library:
import CPromise from "c-promise2";
// const CPromise = require("c-promise2"); // using require
// import CPromise from "c-promise2/dev"; // development version
const chain= CPromise.delay(1000, 'It works!').then(message => console.log('Done', message));
//chain.cancel();
As an alternative you can use any CDN with npn support:
development UMD version with (additional error handling activated)
production UMD version (or minified ~9KB)
Examples
Progress capturing and cancellation
Basic example (Live demo):
import CPromise from 'c-promise';
const delay= (ms, value)=>{
return new CPromise((resolve, reject, {onCancel}) => {
const timer = setTimeout(resolve, ms, value);
onCancel(() => {
clearTimeout(timer);
console.log('clear timeout');
}) // clear internal operations on 'cancel' event
})
}
const promise = CPromise.all([
delay(1000, 'a'),
delay(2000, 'b'),
delay(3000, 'c'),
delay(4000, 'd'),
delay(5000, 'e'),
])
.progress(value=> console.log(`Progress: ${(value * 100).toFixed(1)}%`));
console.log('isPromise:', promise instanceof Promise); // true
(async()=>{
try {
console.log(`Done: `, await promise);
}catch(err){
console.warn(`Failed: ${err}`);
console.log('isCanceled:', promise.isCanceled);
}
})()
setTimeout(()=> promise.cancel(), 3100); // cancel promise after 3100ms
Console output:
isPromise: true
Progress: 20.0%
Progress: 40.0%
Progress: 60.0%
clear timeout
clear timeout
isCanceled: true
Failed: CanceledError: canceled
Process finished with exit code 0
Pause / resume promises
See the live demo
import CPromise from 'c-promise';
function cancelableDelay(ms, value){
return new CPromise(function(resolve, reject, {onCancel, onPause, onResume}){
let timestamp= Date.now();
let timeLeft;
let timer= setTimeout(resolve, ms, value);
onPause(()=>{
console.log(`Pause`);
clearTimeout(timer);
timer=0;
timeLeft= ms - (Date.now()- timestamp);
timestamp= Date.now();
});
onResume(()=>{
console.log(`Resume`);
timer= setTimeout(resolve, timeLeft, value);
});
onCancel(()=>{
console.log(`Cancel`);
timer && clearTimeout(timer);
})
});
}
const chain= cancelableDelay(1000, 123)
.then(
value=> console.log(`Done:`, value),
err=> console.warn(`Fail: ${err}`)
);
setTimeout(()=>{
chain.pause();
setTimeout(()=>{
chain.resume();
}, 5000);
}, 100);
Abortable fetch with timeout
This is how an abortable fetch (live example) with a timeout might look like
function fetchWithTimeout(url, {timeout, ...fetchOptions}= {}) {
return new CPromise((resolve, reject, {signal}) => {
fetch(url, {...fetchOptions, signal}).then(resolve, reject)
}, timeout)
}
const promise= fetchWithTimeout('http://localhost/', {timeout: 5000})
.then(response => response.json())
.then(data => console.log(`Done: `, data), err => console.log(`Error: `, err))
setTimeout(()=> promise.cancel(), 1000);
// you able to call cancel() at any time to cancel the entire chain at any stage
// the related network request will also be aborted
You can use the cp-fetch package which provides a CPromise wrapper for fetch API.

Wrapping axios request
function cancelableAxios(url){
return new CPromise((resolve, reject, {onCancel})=>{
axios.get(url, {
cancelToken: new axios.CancelToken(function executor(cancel) {
onCancel(cancel)
})
}).then(resolve, reject);
});
}
You can use the cp-axios package to get Axios to work with CPromise.
Concurrency limitation:
import CPromise from "c-promise2";
import cpFetch from "cp-fetch";
(async()=>{
await CPromise.all([
'url1',
'url2',
'url3',
'url4',
'url5',
'url6',
], {
mapper: async (url) => {
return cpFetch(url);
},
concurrency: 2
})
console.log('Done');
});
// Or
(async()=>{
await CPromise.all(function*(){
const urls= [
'url1',
'url2',
'url3',
'url4',
'url5',
'url6',
];
for(let url of urls){
yield cpFetch('url1');
}
}, {
concurrency: 2
})
console.log('Done');
})();
Using Generators as an alternative of ECMA async functions
Generally you can use CPromise with ES6 async functions, but if you need some specific functionality
such as progress capturing or cancellation, you need to use generators instead of async functions to make it work.
This is because the async function leads all the nested thenables into its own Promise class,
and there is nothing we can do about it.
Generators allow you to write asynchronous code just in the same way as async functions do, just use yield
instead of await
.
See the live demo
import CPromise from "c-promise2";
const promise= CPromise.from(function*(){
this.innerWeight(12); //optionally set the expected internal progress score of the nested chain
yield CPromise.delay(1000);
yield [CPromise.delay(1000), CPromise.delay(1500)] // resolve chains using CPromise.all([...chains]);
yield [[CPromise.delay(1000), CPromise.delay(1500)]] // resolve chains using CPromise.race([...chains]);
yield new CPromise(resolve=> resolve(true)); // any thenable object will be resolved
return "It works!";
})
.progress(value=> console.log(`Progress: ${value}`))
.then(message=> console.log(`Done: ${message}`));
Related projects
- cp-axios - a simple axios wrapper that provides an advanced cancellation api
- cp-fetch - fetch with timeouts and request cancellation
API Reference
Cancellable Promise with extra features
- CPromise
- ~CPromise ⇐
Promise
- new CPromise(executor, [options])
- instance
- .signal :
AbortSignal
- .isPending ⇒
Boolean
- .isCanceled ⇒
Boolean
- .isCaptured ⇒
Boolean
- .isPaused ⇒
Boolean
- .parent ⇒
CPromise
|null
- .totalWeight([weight]) ⇒
Number
|CPromise
- .innerWeight([weight]) ⇒
Number
|CPromise
- .progress(value, [data]) ⇒
Number
|CPromise
- .propagate(type, data) ⇒
CPromise
- .captureProgress([options]) ⇒
CPromise
- .scopes() ⇒
Array.<CPromise>
- .timeout([ms]) ⇒
Number
|CPromise
- .weight([weight]) ⇒
Number
|CPromise
- .label([label]) ⇒
Number
|CPromise
- .resolve(value) ⇒
CPromise
- .reject(err) ⇒
CPromise
- .pause() ⇒
Boolean
- .resume() ⇒
Boolean
- .cancel([reason])
- .emitSignal(type, data) ⇒
Boolean
- .delay(ms) ⇒
CPromise
- .then(onFulfilled, [onRejected]) ⇒
CPromise
- .catch(onRejected, [filter]) ⇒
CPromise
- .listenersCount(type) ⇒
Number
- .hasListeners(type) ⇒
Boolean
- .once(type, listener) ⇒
CPromise
- .emit(type, ...args) ⇒
CPromise
- .emitHook(type, ...args) ⇒
Boolean
- .signal :
- static
- .isCanceledError(thing) ⇒
boolean
- .delay(ms, value) ⇒
CPromise
- .all(iterable, options) ⇒
CPromise
- .race(thenables) ⇒
CPromise
- .allSettled(iterable, options) ⇒
CPromise
- .from(thing, [resolveSignatures]) ⇒
CPromise
- .isCanceledError(thing) ⇒
- ~EventType :
String
|Symbol
- ~CPromiseExecutorFn :
function
- ~PromiseOptionsObject :
Object
- ~CPromiseOptions :
PromiseOptionsObject
|String
|Number
- ~OnCancelListener :
function
- ~OnPauseListener :
function
- ~OnResumeListener :
function
- ~AllOptions :
object
- ~CPromise ⇐
CPromise~CPromise ⇐ Promise
CPromise class
Kind: inner class of CPromise
Extends: Promise
- ~CPromise ⇐
Promise
- new CPromise(executor, [options])
- instance
- .signal :
AbortSignal
- .isPending ⇒
Boolean
- .isCanceled ⇒
Boolean
- .isCaptured ⇒
Boolean
- .isPaused ⇒
Boolean
- .parent ⇒
CPromise
|null
- .totalWeight([weight]) ⇒
Number
|CPromise
- .innerWeight([weight]) ⇒
Number
|CPromise
- .progress(value, [data]) ⇒
Number
|CPromise
- .propagate(type, data) ⇒
CPromise
- .captureProgress([options]) ⇒
CPromise
- .scopes() ⇒
Array.<CPromise>
- .timeout([ms]) ⇒
Number
|CPromise
- .weight([weight]) ⇒
Number
|CPromise
- .label([label]) ⇒
Number
|CPromise
- .resolve(value) ⇒
CPromise
- .reject(err) ⇒
CPromise
- .pause() ⇒
Boolean
- .resume() ⇒
Boolean
- .cancel([reason])
- .emitSignal(type, data) ⇒
Boolean
- .delay(ms) ⇒
CPromise
- .then(onFulfilled, [onRejected]) ⇒
CPromise
- .catch(onRejected, [filter]) ⇒
CPromise
- .listenersCount(type) ⇒
Number
- .hasListeners(type) ⇒
Boolean
- .once(type, listener) ⇒
CPromise
- .emit(type, ...args) ⇒
CPromise
- .emitHook(type, ...args) ⇒
Boolean
- .signal :
- static
- .isCanceledError(thing) ⇒
boolean
- .delay(ms, value) ⇒
CPromise
- .all(iterable, options) ⇒
CPromise
- .race(thenables) ⇒
CPromise
- .allSettled(iterable, options) ⇒
CPromise
- .from(thing, [resolveSignatures]) ⇒
CPromise
- .isCanceledError(thing) ⇒
new CPromise(executor, [options])
Constructs new CPromise instance
Param | Type | Description |
---|---|---|
executor | CPromiseExecutorFn |
promise executor function that will be invoked in the context of the new CPromiseScope instance |
[options] | CPromiseOptions |
cPromise.signal : AbortSignal
get promise abort signal object
Kind: instance property of CPromise
cPromise.isPending ⇒ Boolean
indicates if the promise is pending
Kind: instance property of CPromise
cPromise.isCanceled ⇒ Boolean
indicates if the promise is pending
Kind: instance property of CPromise
cPromise.isCaptured ⇒ Boolean
indicates if the promise progress is captured
Kind: instance property of CPromise
cPromise.isPaused ⇒ Boolean
indicates if the promise is paused
Kind: instance property of CPromise
cPromise.parent ⇒ CPromise
| null
get parent promise
Kind: instance property of CPromise
cPromise.totalWeight([weight]) ⇒ Number
| CPromise
Set or get the total weight of the inner chains
Kind: instance method of CPromise
Param | Type |
---|---|
[weight] | Number |
cPromise.innerWeight([weight]) ⇒ Number
| CPromise
Set or get the total weight of the inner chains
Kind: instance method of CPromise
Param | Type |
---|---|
[weight] | Number |
cPromise.progress(value, [data]) ⇒ Number
| CPromise
Set promise progress
Kind: instance method of CPromise
Param | Type | Description |
---|---|---|
value | Number |
a number between [0, 1] |
[data] | * |
any data to send for progress event listeners |
cPromise.propagate(type, data) ⇒ CPromise
emit propagate event that will propagate through each promise scope in the chain (bubbling)
Kind: instance method of CPromise
Param | Type | Default | Description |
---|---|---|---|
type | String | symbol |
some type to identify the data kind | |
data | * |
|
some data |
cPromise.captureProgress([options]) ⇒ CPromise
capture initial progress state of the chain
Kind: instance method of CPromise
Param | Type | Description |
---|---|---|
[options] | Object |
|
options.throttle | Number |
set min interval for firing progress event |
options.innerWeight | Number |
set weight of the nested promises |
cPromise.scopes() ⇒ Array.<CPromise>
Returns all parent scopes that are in pending state
Kind: instance method of CPromise
cPromise.timeout([ms]) ⇒ Number
| CPromise
timeout before the promise will be canceled
Kind: instance method of CPromise
Param | Type | Description |
---|---|---|
[ms] | Number |
timeout in ms |
cPromise.weight([weight]) ⇒ Number
| CPromise
Sets the promise weight in progress capturing process
Kind: instance method of CPromise
Returns: Number
| CPromise
- returns weight if no arguments were specified
Param | Type | Description |
---|---|---|
[weight] | Number |
any number greater or equal 0 |
cPromise.label([label]) ⇒ Number
| CPromise
Sets the promise label
Kind: instance method of CPromise
Returns: Number
| CPromise
- returns weight if no arguments were specified
Param | Type | Description |
---|---|---|
[label] | String |
any string |
cPromise.resolve(value) ⇒ CPromise
Resolves the promise with given value
Kind: instance method of CPromise
Param |
---|
value |
cPromise.reject(err) ⇒ CPromise
Rejects the promise with given error
Kind: instance method of CPromise
Param |
---|
err |
cPromise.pause() ⇒ Boolean
Pause promise
Kind: instance method of CPromise
cPromise.resume() ⇒ Boolean
Resume promise
Kind: instance method of CPromise
cPromise.cancel([reason])
throws the CanceledError that cause promise chain cancellation
Kind: instance method of CPromise
Param | Type |
---|---|
[reason] | String | Error |
cPromise.emitSignal(type, data) ⇒ Boolean
Emit a signal of the specific type
Kind: instance method of CPromise
Param | Type |
---|---|
type | String | Symbol |
data | * |
cPromise.delay(ms) ⇒ CPromise
Returns a chain that will be resolved after specified timeout
Kind: instance method of CPromise
Param | Type |
---|---|
ms | Number |
cPromise.then(onFulfilled, [onRejected]) ⇒ CPromise
returns a CPromise. It takes up to two arguments: callback functions for the success and failure cases of the Promise.
Kind: instance method of CPromise
Param | Type |
---|---|
onFulfilled | onFulfilled |
[onRejected] | onRejected |
cPromise.catch(onRejected, [filter]) ⇒ CPromise
Catches rejection with optionally specified Error class
Kind: instance method of CPromise
Param | Type |
---|---|
onRejected | function |
[filter] | Error |
cPromise.listenersCount(type) ⇒ Number
returns listeners count of the specific event type
Kind: instance method of CPromise
Param | Type |
---|---|
type | EventType |
cPromise.hasListeners(type) ⇒ Boolean
checks if there are listeners of a specific type
Kind: instance method of CPromise
Param | Type |
---|---|
type | String | Symbol |
cPromise.once(type, listener) ⇒ CPromise
add 'once' listener
Kind: instance method of CPromise
Param | Type |
---|---|
type | EventType |
listener | function |
cPromise.emit(type, ...args) ⇒ CPromise
emits the event
Kind: instance method of CPromise
Param | Type |
---|---|
type | EventType |
...args |
cPromise.emitHook(type, ...args) ⇒ Boolean
emits event as a hook. If some listener return true, this method will immediately return true as the result. Else if some listener returns false the method will return false after invoking all the listeners
Kind: instance method of CPromise
Param | Type |
---|---|
type | EventType |
...args |
CPromise.isCanceledError(thing) ⇒ boolean
Checks if thing is an CanceledError instance
Kind: static method of CPromise
Param |
---|
thing |
CPromise.delay(ms, value) ⇒ CPromise
Returns a CPromise that will be resolved after specified timeout
Kind: static method of CPromise
Param | Type | Description |
---|---|---|
ms | Number |
delay before resolve the promise with specified value |
value |
CPromise.all(iterable, options) ⇒ CPromise
Returns a single CPromise that resolves to an array of the results of the input promises. If one fails then other promises will be canceled immediately
Kind: static method of CPromise
Param | Type |
---|---|
iterable | Iterable | Generator | GeneratorFunction |
options | AllOptions |
Example
CPromise.all(function*(){
yield axios.get(url1);
yield axios.get(url2);
yield axios.get(url3);
}, {concurrency: 1}).then(console.log)
CPromise.race(thenables) ⇒ CPromise
returns a promise that fulfills or rejects as soon as one of the promises in an iterable fulfills or rejects, with the value or reason from that promise. Other pending promises will be canceled immediately
Kind: static method of CPromise
Param | Type |
---|---|
thenables | Iterable |
CPromise.allSettled(iterable, options) ⇒ CPromise
returns a promise that resolves after all of the given promises have either fulfilled or rejected
Kind: static method of CPromise
Param | Type |
---|---|
iterable | Iterable | Generator | GeneratorFunction |
options | AllOptions |
CPromise.from(thing, [resolveSignatures]) ⇒ CPromise
Converts thing to CPromise using the following rules:
- CPromise instance returns as is
- Objects with special method defined with key
Symbol.for('toCPromise')
will be converted using this method The result will be cached for future calls - Thenable wraps into a new CPromise instance, if thenable has the
cancel
method it will be used for canceling - Generator function will be resolved to CPromise
- Array will be resoled via
CPromise.all
, arrays with one element (e.g.[[1000]]
) will be resolved viaCPromise.race
This method returns null if the conversion failed.
Kind: static method of CPromise
Param | Type | Default |
---|---|---|
thing | * |
|
[resolveSignatures] | boolean |
true |
CPromise~EventType : String
| Symbol
Kind: inner typedef of CPromise
CPromise~CPromiseExecutorFn : function
Kind: inner typedef of CPromise
this: CPromise
Param | Type |
---|---|
resolve | function |
reject | function |
scope | CPromise |
CPromise~PromiseOptionsObject : Object
Kind: inner typedef of CPromise
Properties
Name | Type |
---|---|
label | String |
timeout | Number |
weight | Number |
CPromise~CPromiseOptions : PromiseOptionsObject
| String
| Number
If value is a number it will be considered as the value for timeout option If value is a string it will be considered as a label
Kind: inner typedef of CPromise
CPromise~OnCancelListener : function
Kind: inner typedef of CPromise
Param | Type |
---|---|
reason | CanceledError |
CPromise~OnPauseListener : function
Kind: inner typedef of CPromise
CPromise~OnResumeListener : function
Kind: inner typedef of CPromise
CPromise~AllOptions : object
Kind: inner typedef of CPromise
Properties
Name | Type | Description |
---|---|---|
concurrency | number |
limit concurrency of promise being run simultaneously |
mapper | function |
function to map each element |
ignoreResults | boolean |
do not collect results |
signatures | boolean |
use advanced signatures for vales resolving |
License
The MIT License Copyright (c) 2020 Dmitriy Mozgovoy robotshara@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.