JSPM

  • Created
  • Published
  • Downloads 125
  • Score
    100M100P100Q81447F
  • License MIT

Cancelable promise chain with progress capturing and other extra features

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

Travis (.com) Coverage Status npm David

SYNOPSIS ✨

CPromise is a subclass of the Promise provided by the environment with some extra features like cancellation, timeouts and progress capturing.

In terms of the library the cancellation means rejection of the deepest promise in the chain with a special error subclass.

It supports cancellation of the whole chain, not just a single promise. The cancellation could be handled by the above standing chains, since it's just throwing a special error and invoking onCancel listeners and/or notify subscribers by the signals using AbortController (built-in implementation or native if it's available).

This lib can be used on the backend and frontend sides.

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.

Installation 🔨

Install for node.js using npm/yarn:

$ npm install c-promise2
$ yarn add c-promise2

The package consists pre-built bundles with umd, cjs, mjs versions which can be found in the ./dist/ directory

CDN

Features / Advantages

  • there are no any dependencies (except [native] Promise)
  • browser support
  • 🔥 supports cancellation of the whole chain - rejects the deepest pending promise in the chain
  • supports onCancel event handler to abort some internal work (clear timers, close requests etc.)
  • supports built-in signal interface for API that supports it (like fetch method)
  • proper handling of CanceledError errors manually thrown inside the chain
  • 🔥 progress capturing with result scaling to handle progress of the whole chain (including nested promise chains), useful for long-term operations
  • ability to install the weight for each promise in the chain
  • ability to attach meta info on each setting of the progress
  • the delay method to return promise that will be resolved with the value after timeout
  • static methods all, race support cancellation and will cancel all other pending promises after they resolved
  • the catch method supports error class filtering

Live Example

Live browser example

Live nodejs example

Browser playground with fetch

Playground

  • Clone https://github.com/DigitalBrainJS/c-promise.git repo
  • Run npm install to install dev-dependencies
  • Open playground/basic.js file with a basic example
  • Run this file using npm run playground or npm run playground:watch command to see the result

Usage example

A font-end example of wrapping fetch to the CPromise and handling cancellation using signals (AbortController)

    function cancelableFetch(url) {
        return new CPromise((resolve, reject, {signal}) => {
            fetch(url, {signal}).then(resolve, reject);
        })
    }
    // URL with 5 seconds delay to respond
    const chain= cancelableFetch('https://run.mocky.io/v3/753aa609-65ae-4109-8f83-9cfe365290f0?mocky-delay=5s')
        .then(console.log, console.warn);

    setTimeout(()=> chain.cancel(), 1000);

Handling cancellation with onCancel listeners (see the live demo):

import CPromise from "c-promise";

const timestamp= Date.now();

function log(message, ...values){
    console.log(`[${Date.now()- timestamp}ms] ${message}`, ...values);
}

const delay= (ms, value)=>{
    return new CPromise((resolve, reject, {onCancel}) => {
    const timer = setTimeout(resolve, ms, value);
    
        onCancel(() => {
            log(`clearTimeout`);
            clearTimeout(timer);
        })
    })
}

const chain = delay(1000, 1).label('first chain')
    .then((value)=> delay(1000, value + 1)).label('second chain')
    .then((value)=> delay(1000, value + 1)).label('third chain')
    .then((value)=> delay(1000, value + 1).label('inner chain')).label('fourth chain')
    .then((value)=> delay(1000, value + 1)).label('fifth chain')
    .progress((value, scope)=> log(`Pending progress ${value} (${scope.label()})`));

const echoChainState= ()=>console.log(`Is pending: ${chain.isPending}\nIs canceled: ${chain.isCanceled}`);

echoChainState();

chain
    .then((value) => {
        log(`Done with value '${value}'`); // [1006ms] CanceledError: canceled
    }).label('final')
    .catch((err)=>{
        log(`cancelled with error : ${err} on '${err.scope.label()}'`); // [1006ms] CanceledError: canceled
    }, CPromise.CanceledError)
    .catch(err=>{
        log(`Some other error occurred: ${err}`);
    })
    .finally(() => {
        echoChainState();
    });

//setTimeout(()=> chain.cancel(), 3500); // Close the chain after 3500ms

The output of the code above:

Is pending: true
Is canceled: false
[1003ms] Pending progress 0.2 (first chain)
[2004ms] Pending progress 0.4 (second chain)
[3004ms] Pending progress 0.6 (third chain)
[4004ms] Pending progress 0.8 (fourth chain)
[5006ms] Pending progress 1 (fifth chain)
[5006ms] Done with value '5'
Is pending: false
Is canceled: false

Process finished with exit code 0

Uncomment the last line to cancel the chain after 3500ms. The output will be as follows:

Is pending: true
Is canceled: false
[1002ms] Pending progress 0.2 (first chain)
[2003ms] Pending progress 0.4 (second chain)
[3004ms] Pending progress 0.6 (third chain)
[3508ms] clearTimeout
[3509ms] cancelled with error : CanceledError: canceled on 'inner chain'
Is pending: false
Is canceled: true

Process finished with exit code 0

API Reference

Cancellable Promise with extra features

CPromise~CPromiseScope ⇐ TinyEventEmitter

Scope for CPromises instances

Kind: inner class of CPromise
Extends: TinyEventEmitter

new CPromiseScope(resolve, reject, options)

Constructs PromiseScope instance

Param Type
resolve function
reject function
options PromiseScopeOptions

cPromiseScope.signal : AbortSignal

get promise abort signal object

Kind: instance property of CPromiseScope

cPromiseScope.isPending ⇒ Boolean

indicates if the promise is pending

Kind: instance property of CPromiseScope

cPromiseScope.isCanceled ⇒ Boolean

indicates if the promise is pending

Kind: instance property of CPromiseScope

cPromiseScope.onCancel(listener)

registers the listener for cancel event

Kind: instance method of CPromiseScope

Param Type
listener function

cPromiseScope.progress([value], [data])

Set promise progress

Kind: instance method of CPromiseScope

Param Type Description
[value] Number a number between [0, 1]
[data] * any data to send for progress event listeners

cPromiseScope.propagate(type, data) ⇒ CPromiseScope

emit propagate event that will propagate through each promise scope in the chain (bubbling)

Kind: instance method of CPromiseScope

Param Type Default Description
type String | Symbol some type to identify the data kind
data * some data

cPromiseScope.captureProgress() ⇒ CPromiseScope

capture initial progress state of the chain

Kind: instance method of CPromiseScope

cPromiseScope.scopes() ⇒ Array.<CPromiseScope>

Returns all parent scopes that are in pending state

Kind: instance method of CPromiseScope

cPromiseScope.timeout(value) ⇒ Number | this

timeout before the promise will be canceled

Kind: instance method of CPromiseScope

Param Type Description
value Number timeout in ms

cPromiseScope.weight(weight) ⇒ Number | CPromiseScope

Sets the promise weight in progress capturing process

Kind: instance method of CPromiseScope
Returns: Number | CPromiseScope - returns weight if no arguments were specified

Param Type Description
weight Number any number grater or equal 0

cPromiseScope.label(label) ⇒ Number | CPromiseScope

Sets the promise label

Kind: instance method of CPromiseScope
Returns: Number | CPromiseScope - returns weight if no arguments were specified

Param Type Description
label String any string

cPromiseScope.resolve(value)

Resolves the promise with given value

Kind: instance method of CPromiseScope

Param
value

cPromiseScope.reject(err)

Rejects the promise with given error

Kind: instance method of CPromiseScope

Param
err

cPromiseScope.done(err, value)

Resolves or rejects the promise depending on the arguments

Kind: instance method of CPromiseScope

Param Description
err error object, if specified the promise will be rejected with this error, resolves otherwise
value

cPromiseScope.cancel(reason)

throws the CanceledError that cause promise chain cancellation

Kind: instance method of CPromiseScope

Param Type
reason String | Error

CPromiseScope.execute(executor, resolve, reject, options) ⇒ CPromiseScope

Executes the promise executor in the PromiseScope context

Kind: static method of CPromiseScope

Param Type
executor CPromiseExecutorFn
resolve
reject
options

CPromise~CPromise ⇐ Promise

CPromise class

Kind: inner class of CPromise
Extends: Promise

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.isPending ⇒ Boolean

indicates if the promise is pending

Kind: instance property of CPromise

cPromise.isCanceled ⇒ Boolean

indicates if promise has been canceled

Kind: instance property of CPromise

cPromise.progress(listener) ⇒ Number | CPromise

returns chains progress synchronously or adds a progress event listener if the argument was specified

Kind: instance method of CPromise

Param Type
listener function

cPromise.captureProgress() ⇒ CPromise

Kind: instance method of CPromise
See: CPromiseScope.captureProgress

cPromise.cancel(reason) ⇒ Boolean

cancel the promise chain with specified reason

Kind: instance method of CPromise
Returns: Boolean - true if success

Param Type
reason String

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.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(thenables) ⇒ 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
thenables Iterable

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~PromiseScopeOptions : Object

Kind: inner typedef of CPromise
Properties

Name Type Description
label String the label for the promise
weight= Number 1 - the progress weight of the promise
timeout= Number 0 - max pending time

CPromise~onFulfilled : function

Kind: inner typedef of CPromise
this: CPromiseScope

Param Type
value
scope CPromiseScope

CPromise~onRejected : function

Kind: inner typedef of CPromise
this: CPromiseScope

Param Type
err
scope CPromiseScope

CPromise~AttachOnCancelHandler : function

Kind: inner typedef of CPromise

CPromise~ExecutorAPI : object

Kind: inner typedef of CPromise
Properties

Name Type
onCancel AttachOnCancelHandler

CPromise~CPromiseExecutorFn : function

Kind: inner typedef of CPromise
this: CPromiseScope

Param Type
resolve function
reject function
api ExecutorAPI

CPromise~CPromiseExecutorFn : function

Kind: inner typedef of CPromise

Param Type
resolve function
reject function

CPromise~CPromiseOptions : Object | 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 label

Kind: inner typedef of CPromise

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.