UNPKG

7.93 kBMarkdownView Raw
1# async-abort
2
3[![npm version](https://img.shields.io/npm/v/async-abort.svg?style=flat-square)](https://www.npmjs.org/package/async-abort)
4[![install size](https://packagephobia.now.sh/badge?p=async-abort)](https://packagephobia.now.sh/result?p=async-abort)
5[![bundle size](https://badgen.net/bundlephobia/min/async-abort)](https://badgen.net/bundlephobia/min/async-abort)
6[![npm downloads](https://img.shields.io/npm/dm/async-abort.svg?style=flat-square)](http://npm-stat.com/charts.html?package=async-abort)
7
8
9
10A 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.
11AsyncAbort 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.
12
13## Table of Contents
14
15 - [Features](#features)
16 - [Browser Support](#browser-support)
17 - [Installing](#installing)
18 - [Preventing Memory leaks in React Component](#preventing-memory-leaks-in-react-component)
19 - [Other Examples](#other-examples)
20 - [Resources](#resources)
21 - [Credits](#credits)
22 - [License](#license)
23
24## Features
25
26- Ability to prevent execution of actions (then, catch, finally blocks) that happen when a [promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) returned from async function settles.
27- Useful in Preventing Memory leaks resulting in asynchronous code in React components
28- works with any kind of promises (native or bluebord or any other polyfills)
29## Browser Support
30
31![Chrome](https://raw.github.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png) | ![Firefox](https://raw.github.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png) | ![Safari](https://raw.github.com/alrra/browser-logos/master/src/safari/safari_48x48.png) | ![Opera](https://raw.github.com/alrra/browser-logos/master/src/opera/opera_48x48.png) | ![Edge](https://raw.github.com/alrra/browser-logos/master/src/edge/edge_48x48.png) | ![IE](https://raw.github.com/alrra/browser-logos/master/src/archive/internet-explorer_9-11/internet-explorer_9-11_48x48.png) |
32--- | --- | --- | --- | --- | --- |
33Latest ✔ | Latest ✔ | Latest ✔ | Latest ✔ | Latest ✔ | 11 ✔ |
34
35## Installing
36
37Using npm:
38
39```bash
40$ npm install async-abort
41```
42
43Using yarn:
44
45```bash
46$ yarn add async-abort
47```
48
49
50## Preventing Memory leaks in React Component
51A React Component that will leak:
52 ```javascript
53
54 function ALeakyTodoComponent({ userId }) {
55 const [todos, setTodos] = useState([]);
56 const [failed, setFailed] = useState(false);
57
58 useEffect(() => {
59 // on mount
60 fetchTodosOfUser(userId)
61 .then((resp) => {
62 setTodos(resp.todos);
63 })
64 .catch((err) => {
65 setFailed(true);
66 });
67 }, [userId]);
68
69 return (<div>
70 { failed && <FailedMsg/>}
71 {todos.map((todo) => (
72 <div>
73 <h1>{todo.title}</h1>
74 <p>{todo.description}</p>
75 </div>
76 ))}
77 </div>)
78 }
79 ```
80
81 Now what happens when the above component is mounted and umounted immediately
82 1. the `fetchTodosOfUser` is called on mount and it holds the references
83 to the `setTodos` and `setFailed` callbacks
84 2. while the promise is still being settled the component will unmount,
85 in order for component to completely unmount and garbage collected, all the references must be cleared.
86 but the promise holds the references of the setState callbacks untill it settles
87 3. this will stop the component from garbage collected and leads to memory leak
88 4. even if you use AbortController or some flags to
89 stop setting the state in your code, the references are still attached and it will not prevent the memory leak
90
91Using AsyncAbort to prevent this leak:
92
93```javascript
94
95 import AsyncAbort from 'async-abort';
96
97 function ANonLeakyTodoComponent({ userId }) {
98 const [todos, setTodos] = useState([]);
99 const [failed, setFailed] = useState(false);
100 useEffect(() => {
101 // on mount
102 const cancel = new AsyncAbort(fetchTodosOfUser, [userId])
103 .then((resp) => {
104 setTodos(resp.todos);
105 })
106 .catch((err) => {
107 setFailed(true);
108 })
109 .call();
110 return () => {
111 cancel();
112 }
113 }, [userId]);
114
115 return (<div>
116 { failed && <FailedMsg/>}
117 {todos.map((todo) => (
118 <div>
119 <h1>{todo.title}</h1>
120 <p>{todo.description}</p>
121 </div>
122 ))}
123 </div>)
124 }
125```
126
127 Now what happens when the above component is mounted and umounted immediately
128 1. the `fetchTodosOfUser` is called on mount through AsyncAbort
129 2. the component gets unmounted while the promise is still being settled and
130 `cancel()` is called in cleanup method of hook this will remove the references
131 of then,catch,finally callbacks which are attached to the `fetchTodoOfUser`
132 **note** cancel won't stop promise from being settling
133 3. after calling cancel() no more references of component are held, the component is garbage collected.
134 4. thus no more memory leaks
135
136
137## Other Examples
138
139### note: CommonJS usage
140To get TypeScript typings (for intellisense / autocomplete) while using CommonJS imports with `require()` use the following approach:
141
142```js
143const AsyncAbort = require('async-abort').default;
144
145// AsyncAbort.<method> will now provide autocomplete and parameter typings
146```
147
148Example for calling an `Async Function` or `Any Promise returning Function`
149
150```js
151import AsyncAbort from 'async-abort';
152
153async function anAsyncFunc(arg1, arg2) {
154 // does some operations
155 // throws an error or returns a value
156}
157
158new AsyncAbort(anAsyncFunc, [arg1Value, arg2Value])
159 .then((resp) => {
160 // code when promise resolves
161 }).catch((err) => {
162 // code when promise rejects
163 }).finally(() => {
164 // similar to finally block
165 }).call();
166
167function somePromiseReturningFunc(arg1, arg2) {
168 // returns a promise
169 return new Promise((resolve, reject) => {
170 // either rejects or resolves
171 });
172}
173
174new AsyncAbort(somePromiseReturningFunc, [arg1Value, arg2Value])
175 .then((resp) => {
176 // code when promise resolves
177 }).catch((err) => {
178 // code when promise rejects
179 }).finally(() => {
180 // similar to finally block
181 }).call();
182
183```
184Action Blocks can be omitted
185
186```js
187 // then and finally are omitted
188 new AsyncAbort(somePromiseReturningFunc, [arg1Value, arg2Value])
189 .catch((err) => {
190 ...
191 }).call();
192
193 // finally is omitted
194 new AsyncAbort(somePromiseReturningFunc, [arg1Value, arg2Value])
195 .then((val) => {
196 ...
197 }).catch((resp) => {
198 ...
199 }).call();
200
201```
202**note** : `.call()` is necessary to call the async function that is passed
203
204Cancelling execution of Action blocks
205
206```js
207
208const cancel = new AsyncAbort(somePromiseReturningFunc, [arg1Value, arg2Value])
209 .then((val) => {
210 ...
211 }).catch((resp) => {
212 ...
213 }).call();
214
215 // to prevent execution of Action blocks (then, catch, finally)
216 cancel();
217```
218
219## Resources
220
221* [Changelog](https://github.com/mohanteja1/async-abort/blob/master/CHANGELOG.md)
222
223
224## Credits
225 - to setup the environment for building this npm package I used code from this [repo](https://github.com/GeorgianStan/framework-for-building-libraries)
226 - used readme file from [axios](https://github.com/axios/axios) project as a template for this readme file
227## License
228
229[MIT](./LICENSE)