Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

regrettable

Package Overview
Dependencies
Maintainers
1
Versions
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

regrettable

A JS/TS async operations cancellation module over native promises.

  • 0.0.1
  • latest
  • Source
  • npm
  • Socket score

Version published
Maintainers
1
Created
Source

Regrettable

A JS/TS async operations cancellation module over native promises (does not exist yet).

Background

Itay is using Bluebird promises in his project. While he enjoys the API in general, the main reason for not switching to native promises is its sound and useful cancellation API.

He loves using async/await but cannot use Node's native support for async functions - it breaks the cancellation propagation of Bluebird promises.

Since he is also using TypeScript (for many reasons), a solution was found in cancelable-awaiter that makes Bluebird cancellation work in conjunction with async functions - as long as they are transpiled by TypeScript instead of being used natively.

There is willingness from Node/v8 Citation Needed to expose hooks that enable experimentation with cancellation APIs for (at least) async functions over native promises (i.e. without a dependency on Bluebird).

Motivation

Itay would like to switch to native promises as long as he gets reasonable cancellation features. His idea is to create a module that depends on a minimal set of hooks that may be later exposed by Node and provide a minimal viable API for canceling async operations.

An additional requirement is that the hooks could be added to TypeScript today (similar to the way the cancelable-awaiter module enabled cancellation propagation) so that he can switch to native promises right away and, hopefully, in the future switch to native async functions when similar hooks will be exposed by Node.

API by example

This is a draft of how the API should work, using simple examples.

Opt-in

Cancellation of async functions is opt-in:

import {cancelable, cancel} from 'regrettable';

// Normal async function cannot be canceled:
async function randomAsync() {
    // Line I:
    console.log("Generating a random number...");

    try {
        const randomNumber = await Math.random();
        // Line II:
        console.log("Generated a random number:", randomNumber);

        return randomNumber;
    }
    finally {
        // Line III:
        console.log("Cleaning up...");
    }
}

// Same as randomAsync but can be canceled:
const cancelableRandomAsync = cancelable(randomAsync);

// Line I will be executed:
const cancelableRandomPromise = cancelableRandomAsync();

// Only line III will be executed:
cancel(cancelableRandomPromise);

// Line I will be executed:
const randomPromise = randomAsync();

// Does nothing (TBD - or throws, or issues warning):
cancel(randomPromise);
// Lines II and III will both eventually be executed.

Propagation

When cancelable functions are composed, the cancel signal propagates upstream:

const delegate = cancelable(async doSomethingAsync => {
    await doSomethingAsync();
});

// Line I will be executed:
const cancelablePropagatingRandomPromise = delegate(cancelableRandomAsync);

// Only line III will be executed:
cancel(cancelablePropagatingRandomPromise);

However, since cancellations are opt-in, the cancel signal does not propagate to non-cancellable functions. Instead, it simply suppresses subsequent onFulfilled and onRejected (and onFinally) callbacks:

// Line I will be executed:
const cancelableNonPropagatingRandomPromise = delegate(/* non-cancelable version: */randomAsync);

cancelableNonPropagatingRandomPromise.then(randomNumber => {
    // Line IV:
    console.log("Got random number:", randomNumber);
});

// Lines II and III will both eventually be executed, but not line IV:
cancel(cancelableNonPropagatingRandomPromise);

Promises are not cancelable

Though, in the examples above, we repeatedly invoked statements such as cancel(promise) the fact is that the promises themselves were not canceled (as they are merely placeholders for values) but the underlying async function that produced them directly was canceled.

By default, calling cancel(promise) with an arbitrary promise instance would have no effect (TBD - perhaps a warning or an error). As a convenience, one can wrap a promise with a cancelable async function in the following way:

const wrappedRandomPromise = cancelable(randomPromise);

wrappedRandomPromise.then(randomNumber => {
    // Line V:
    console.log("Got random number:", randomNumber);
});

// Lines II and III will both eventually be executed, but not line V:
cancel(wrappedRandomPromise);

Note that the above code does not make randomPromise truly cancelable in any sense, it simply wraps the promise in order to allow the consumer to "unregister" from it.

Required Hooks

TBD

FAQ

TBD

FAQs

Package last updated on 12 Jun 2018

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc