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

async-abort

v2.0.0

Published

a cancelable promise utility helps prevent memory leaks in react components

Downloads

207

Readme

async-abort

npm version install size bundle size npm downloads

A canceleable promise utility which helps solve memory leak in asynchronous code in a react components which cannot be solved using AbortController or other hooks which uses similar type of cancelling mechanisms. AsyncAbort internally uses dont care policy for the promise cancellation ie.. it won't stop the promises from settling but it stops callbacks attached from being called. It does so by detaching the loosely attached callbacks from promise and preventing memory references of these callbacks from being held by promise call which can cause memory leak if not.

Table of Contents

Features

  • Ability to prevent execution of actions (then, catch, finally blocks) that happen when a promise returned from async function settles.
  • Useful in Preventing Memory leaks resulting in asynchronous code in React components
  • works with any kind of promises (native or bluebord or any other polyfills)

Browser Support

Chrome | Firefox | Safari | Opera | Edge | IE | --- | --- | --- | --- | --- | --- | Latest ✔ | Latest ✔ | Latest ✔ | Latest ✔ | Latest ✔ | 11 ✔ |

Installing

Using npm:

$ npm install async-abort

Using yarn:

$ yarn add async-abort

Preventing Memory leaks in React Component

A React Component that will leak:

  
  function ALeakyTodoComponent({ userId }) {
      const [todos, setTodos] = useState([]);
      const [failed, setFailed] = useState(false);

      useEffect(() => {
         // on mount 
         fetchTodosOfUser(userId)
           .then((resp) => {
             setTodos(resp.todos);
           })
           .catch((err) => {
             setFailed(true);
           });
      }, [userId]);

      return (<div>
        { failed && <FailedMsg/>}
        {todos.map((todo) => (
            <div>
               <h1>{todo.title}</h1>
               <p>{todo.description}</p>
            </div>
        ))}
      </div>)
  }

Now what happens when the above component is mounted and umounted immediately

  1. the fetchTodosOfUser is called on mount and it holds the references to the setTodos and setFailed callbacks
  2. while the promise is still being settled the component will unmount, in order for component to completely unmount and garbage collected, all the references must be cleared. but the promise holds the references of the setState callbacks untill it settles
  3. this will stop the component from garbage collected and leads to memory leak
  4. even if you use AbortController or some flags to stop setting the state in your code, the references are still attached and it will not prevent the memory leak

Using AsyncAbort to prevent this leak:

  
  import AsyncAbort from 'async-abort';

  function ANonLeakyTodoComponent({ userId }) {
       const [todos, setTodos] = useState([]);
       const [failed, setFailed] = useState(false);
       useEffect(() => {
          // on mount 
         const cancel = new AsyncAbort(fetchTodosOfUser, [userId])
            .then((resp) => {
              setTodos(resp.todos);
            })
            .catch((err) => {
              setFailed(true);
            })
            .call();
        return () => {
           cancel();
        }
       }, [userId]);

       return (<div>
         { failed && <FailedMsg/>}
         {todos.map((todo) => (
             <div>
                <h1>{todo.title}</h1>
                <p>{todo.description}</p>
             </div>
         ))}
       </div>)
   }

Now what happens when the above component is mounted and umounted immediately

  1. the fetchTodosOfUser is called on mount through AsyncAbort
  2. the component gets unmounted while the promise is still being settled and cancel() is called in cleanup method of hook this will remove the references of then,catch,finally callbacks which are attached to the fetchTodoOfUser note cancel won't stop promise from being settling
  3. after calling cancel() no more references of component are held, the component is garbage collected.
  4. thus no more memory leaks

Other Examples

note: CommonJS usage

To get TypeScript typings (for intellisense / autocomplete) while using CommonJS imports with require() use the following approach:

const AsyncAbort = require('async-abort').default;

// AsyncAbort.<method> will now provide autocomplete and parameter typings

Example for calling an Async Function or Any Promise returning Function

import AsyncAbort from 'async-abort';

async function anAsyncFunc(arg1, arg2) {
    // does some operations
    // throws an error or returns a value
}

new AsyncAbort(anAsyncFunc, [arg1Value, arg2Value])
    .then((resp) => {
      // code when promise resolves
    }).catch((err) => {
      // code when promise rejects
    }).finally(() => {
      // similar to finally block 
    }).call();

function somePromiseReturningFunc(arg1, arg2) {
  // returns a promise
  return new Promise((resolve, reject) => {
      // either rejects or resolves
  });
}

new AsyncAbort(somePromiseReturningFunc, [arg1Value, arg2Value])
    .then((resp) => {
      // code when promise resolves
    }).catch((err) => {
      // code when promise rejects
    }).finally(() => {
      // similar to finally block 
    }).call();

Action Blocks can be omitted

 // then and finally are omitted
 new AsyncAbort(somePromiseReturningFunc, [arg1Value, arg2Value])
    .catch((err) => {
        ...
    }).call();

 // finally is omitted
 new AsyncAbort(somePromiseReturningFunc, [arg1Value, arg2Value])
    .then((val) => {
        ...
    }).catch((resp) => {
        ...
    }).call();

note : .call() is necessary to call the async function that is passed

Cancelling execution of Action blocks


const cancel = new AsyncAbort(somePromiseReturningFunc, [arg1Value, arg2Value])
    .then((val) => {
        ...
    }).catch((resp) => {
        ...
    }).call();
 
 // to prevent execution of Action blocks (then, catch, finally)
 cancel();

Resources

Credits

  • to setup the environment for building this npm package I used code from this repo
  • used readme file from axios project as a template for this readme file

License

MIT