npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@theisleoffavalon/cancellable

v1.0.3

Published

Cancellable promises

Downloads

4

Readme

Cancellable

When promises were implemented they did not come with a built-in mechanism to implement cancellation like you might see in some other Future type implementations. Normally this isn't a huge issue but there are definitely instances where you need to be able to stop a promise from resolving/rejecting.

Installation

Just use your favorite package manager to install.

npm install @theisleoffavalon/cancellable
yarn add @theisleoffavalon/cancellable
pnpm install @theisleoffavalon/cancellable

Basic Usage

One example of a time where you want to be really careful about if a promise will resolve is with React. In React you can't modify a React component once it has become unmounted from the page. If you have a component that renders a list of items that are retrieved from a REST endpoint, you might start a request either on the first render or right before it and then when the requests finishes render some content based on the results. Something like this:

import React, {
    FunctionComponent,
    ReactElement,
    useEffect,
    useState,
} from 'react';

const NameList: FunctionComponent = (): ReactElement => {
    const [ names, setNames ] = useState([]);

    useEffect((): void => {
        fetch('http://example.com/names')
            .then((response: Response) => {
                // You would normally handle errors and what not here

                return response.json();
            })
            .then(setNames);
    }, []);

    return (
        <ul>
            {names.map((name: string) => {
                return <li>{name}</li>;
            })}
        </ul>
    );
};

This will work fine up until you have a situation where the component gets unmounted before the request resolves. In that situation you'll get an exception from React when you try to update the state on an unmounted component.

One solution to this problem is adding cancellation to promises. Using this library you could rewrite this component like so:

import React, {
    FunctionComponent,
    ReactElement,
    useEffect,
    useState,
} from 'react';

import { Cancellable } from '@theisleoffavalon/cancellable';

const NameList: FunctionComponent = (): ReactElement => {
    const [ names, setNames ] = useState([]);

    useEffect((): ((): void) => {
        const cancellable = new Cancellable();

        cancellable.wrap(fetch('http://example.com/names'))
            .then((response: Response) => {
                // You would normally handle errors and what not here

                return response.json();
            })
            .then(setNames);

        return (): void => {
            cancellable.cancel('React component unmounted');
        };
    }, []);

    return (
        <ul>
            {names.map((name: string) => {
                return <li>{name}</li>;
            })}
        </ul>
    );
};

Now if the component unmounts before the fetch resolves, the promise is cancelled and nothing happens.

With a timeout

Continuing on with the previous example, maybe you want to add some extra handling in so that if a request takes too long that it gets auto cancelled and rejected.

Note that in a more realistic situation you would use a timeout when you have multiple long running operations happening that you want to stop if they're taking too long.

import React, {
    FunctionComponent,
    ReactElement,
    useEffect,
    useState,
} from 'react';

import { Cancellable } from '@theisleoffavalon/cancellable';

const NameList: FunctionComponent = (): ReactElement => {
    const [ names, setNames ] = useState([]);

    useEffect((): ((): void) => {
        const cancellable = new Cancellable().withTimeout(60000);

        cancellable.wrap(fetch('http://example.com/names'))
            .then((response: Response) => {
                // You would normally handle errors and what not here

                return response.json();
            })
            .then(setNames);

        return (): void => {
            cancellable.cancel('React component unmounted');
        };
    }, []);

    return (
        <ul>
            {names.map((name: string) => {
                return <li>{name}</li>;
            })}
        </ul>
    );
};

We've simply moved from const cancellable = new Cancellable(); to const cancellable = new Cancellable().withTimeout(60000); which will automatically cancel the promise after one minute unless the promise resolves on its own first.