UNPKG

12 kBMarkdownView Raw
1<a><img src="https://img.shields.io/bundlephobia/minzip/async-af.svg?style=for-the-badge&amp;label=size&amp;colorB=466EF1" alt="npm package size (min + gzip)"></a>
2<a href="https://www.npmjs.com/package/async-af" target=_blank><img src="https://img.shields.io/npm/v/async-af.svg?style=for-the-badge&colorB=cb3837" alt="npm version"></a>
3<a href="https://yarnpkg.com/en/package/async-af" target=_blank><img src="https://img.shields.io/npm/v/async-af.svg?label=yarn&style=for-the-badge&colorB=2c8ebb" alt="yarn version"></a>
4<a href="https://unpkg.com/async-af/" target=_blank><img src="https://img.shields.io/npm/v/async-af.svg?style=for-the-badge&colorB=ffcc2f&label=unpkg" alt="unpkg version"></a>
5<a href="https://codecov.io/gh/AsyncAF/AsyncAF" target=_blank><img src="https://img.shields.io/codecov/c/github/AsyncAF/AsyncAF.svg?style=for-the-badge&label=codecov&colorB=brightgreen" alt=codecov></a>
6<a href="https://github.com/AsyncAF/AsyncAF/blob/master/README.md#license"><img src="https://img.shields.io/npm/l/async-af.svg?style=for-the-badge&colorB=aaaaaa" alt="MIT License"></a>
7
8<p align=center><a href="https://async-af.js.org" target=_blank><img src="https://cdn.rawgit.com/AsyncAF/AsyncAF/1ce388a7/docs/custom/assets/async-af-logo.png"></a></p>
9
10<br>
11
12Working with promises or async/await?
13
14Use AsyncAF to transform your code into beautiful asynchronous JavaScript chains, with methods similar to the ones we all know (and love! 😍) such as `map`, `forEach`, `filter`, `reduce`, and more.
15
16<a href="https://async-af.js.org/AsyncAF" target=_blank>
17 Check out the docs
18</a> for all available methods. 💙
19<br>
20
21## Usage
22
23```js
24const AsyncAF = require('async-af');
25
26function getActiveUsers(userIds) {
27 return AsyncAF(userIds)
28 // map user ids to user objects with an async function
29 .mapAF(async userId => {
30 const user = await fetch(`fake-game-api/users/${userId}`);
31 return user.json();
32 })
33 // filter by active users
34 .filterAF(user => user.isActive);
35}
36```
37
38AsyncAF methods are await-able and then-able.
39
40```js
41async function sendMsgToActiveUsers(msg) {
42 const activeUsers = await getActiveUsers([1, 2, 3]);
43 // send each active user a msg in series
44 await AsyncAF(activeUsers).series.forEachAF(async ({id}) => {
45 await sendMsg(id, msg); // hypothetical msg service that's rate-limited
46 });
47 console.log('message sent!');
48}
49
50function doSomethingElseWithActiveUsers() {
51 return getActiveUsers([1, 2, 3]).then(activeUsers => {
52 // ... do something else
53 });
54}
55```
56
57If a `Promise` is passed into <a href="https://async-af.js.org/AsyncAF" target=_blank>`AsyncAF`</a>, it will be settled before a method processes it.
58
59```js
60const userMsg = Promise.resolve('I\'m [restricted word] AF right now')
61
62const msgContainsBadWord = (msg, word = '[restricted word]') => AsyncAF(msg).includesAF(word);
63
64msgContainsBadWord(userMsg); // resolves to true
65```
66
67`Array` methods will settle any promises in an array before processing them.
68
69```js
70const findHighScoringUser = () => AsyncAF([
71 fetch('fake-game-api/users/1').then(user => user.json()), // {id: 1, name: Aiden, score: 9001, ...}
72 {id: 2, name: 'Bill', score: 3600, /* ... */},
73 {id: 3, name: 'Cari', score: 5800, /* ... */},
74])
75 .findAF(({score}) => score > 9000);
76
77findHighScoringUser(); // resolves to {id: 1, name: Aiden, score: 9001, ...}
78```
79
80**Note**: All `'AF'` methods have an `'AF-less'` alias so you can choose whether or not to make it obvious that they're AsyncAF methods.
81
82For example:
83
84```js
85const promises = [1, 2, 3].map(n => Promise.resolve(n));
86
87AsyncAF(promises).map(n => n * 2).filter(n => n !== 4).forEach(n => console.log(n));
88// or
89AsyncAF(promises).mapAF(n => n * 2).filterAF(n => n !== 4).forEachAF(n => console.log(n));
90// both log 2 then 6
91```
92
93## Installation 💾
94
95Easy peasy, just
96
97`$ npm install --save async-af`,
98
99right?
100
101 ⚠️ Not so fast; there's actually several ways to include AsyncAF in your project/production site from easy to more complex:
102
103<details><summary>Easy 👍</summary><br>
104🔹 <strong>npm:</strong> <code>$ npm install --save async-af</code>
105
106🔸 <strong>yarn:</strong> <code>$ yarn add async-af</code>
107
108🔹 <strong>bower:</strong> <code>async-af</code> is no longer published to bower. To continue using it with bower, look into <a href="https://github.com/mjeanroy/bower-npm-resolver" target=_blank><code>bower-npm-resolver</code></a>.
109
110🔸 <strong>cdn:</strong> See the table for which script tag to use:
111
112<table align=left><th>mode</th><th>browsers</th><th>script tag</th>
113<tr><td>development</td><td>modern (ES6+)</td><td><code class=language-html>&lt;script src="https&#58;//unpkg.com/async-af/index.js">&lt;/script></code></td></tr>
114<tr><td>development</td><td>legacy (ES5+)</td><td><code class=language-html>&lt;script src="https&#58;//unpkg.com/async-af/legacy/index.js">&lt;/script></code></td></tr>
115<tr><td>production</td><td>modern (ES6+)</td><td><code class=language-html>&lt;script src="https&#58;//unpkg.com/async-af/min.js">&lt;/script></code></td></tr>
116<tr><td>production</td><td>legacy (ES5+)</td><td><code class=language-html>&lt;script src="https&#58;//unpkg.com/async-af/legacy/min.js">&lt;/script></code></td></tr>
117</table><br>
118</details>
119<br>
120<details><summary>More Complex 🤔</summary><br>
121
122🔹 <strong>scoped packages:</strong>
123
124>Instead of pulling in the entire AsyncAF library, you can install smaller standalone packages for each of the AsyncAF methods you intend to use; for example, <code>@async-af/map</code> and/or <code>@async-af/filter</code>; see further instructions in the documentation for <a href="https://async-af.js.org/AsyncAfWrapper" target=_blank>AsyncAfWrapper</a> and <a href="https://async-af.js.org/AsyncAfWrapper#use" target=_blank>AsyncAfWrapper.use</a>.
125
126🔸 <strong>scoped packages + `babel-plugin-transform-imports`:</strong>
127
128>If you use more than a few AsyncAF scoped packages in a file, you might start to build a wall of `import` statements to pull them all in. If this is an eyesore for you, look into <a href="https://www.npmjs.com/package/babel-plugin-transform-imports" target="_blank"><code>babel-plugin-transform-imports</code></a> and condense that ugly wall down to a single `import` statement! See <a href="https://async-af.js.org/tutorial-TOO_MANY_IMPORTS" target=_blank>Wrapper/Use: Too Many 🤬 Imports!?</a> for a tutorial.
129
130🔹 <strong>es modules:</strong>
131
132>AsyncAF as well as its scoped packages are also published as es modules. This gives an opportunity to conditionally load `async-af` with ES6+ features in modern browsers and `async-af` with ES5-compatible features in legacy browsers.
133>
134>Using the cdn scripts as an example:
135>
136><pre class=prettyprint>
137><code><code class=language-html>&lt;script type="module" src="https&#58;//unpkg.com/async-af/esm/index.js">&lt;/script></code>
138><code class=language-html>&lt;script nomodule src="https&#58;//unpkg.com/async-af/legacy/index.js">&lt;/script></code></code></pre>
139>
140>or minimized for production:
141>
142><pre class=prettyprint>
143><code><code class=language-html>&lt;script type="module" src="https&#58;//unpkg.com/async-af/esm/min.js">&lt;/script></code>
144><code class=language-html>&lt;script nomodule src="https&#58;//unpkg.com/async-af/legacy/min.js">&lt;/script></code></code></pre>
145
146>The script with <code class="language-html prettyprint">&lt;script type="module"></code> will load in any browser capable of loading es modules, while the script with <code class="language-html prettyprint">&lt;script nomodule></code> will act as a fallback for legacy browsers.
147>
148>See <a href="https://philipwalton.com/articles/deploying-es2015-code-in-production-today/" target=_blank>here</a> and <a href="https://jakearchibald.com/2017/es-modules-in-browsers/" target=_blank>here</a> for further reading on this strategy.
149</details>
150<br>
151
152## A couple notes on performance 🚀
153
154#### Built on Promises
155
156Despite AsyncAF's name (Async/Await Fun), its source code is written entirely without the use of `async/await`. Its chainable asynchronous JavaScript methods _are_, however, highly useful when _your_ code makes use of `async/await` or `Promises`. This is important for performance because transpiling an `async function` with babel currently <a href="https://medium.com/@bluepnume/even-with-async-await-you-probably-still-need-promises-9b259854c161" target=_blank>results in some loooong code</a> due to pulling in things like <a href="https://facebook.github.io/regenerator/" target=_blank>Facebook's regenerator</a> and others to make it work.
157
158Because AsyncAF instead runs your code with Promises behind the scenes, there's no need to transpile `async/await` in its ES6 or ES5-compatible distributions. This boils down to much smaller bundles when compared to an equivalent async library written _with_ `async/await`.
159
160#### Use <a href="https://async-af.js.org/AsyncAF#series" target=_blank>`series`</a> wisely
161
162The majority of AsyncAF's `Array` methods process promises in parallel by default. However, many methods have an option to process promises in series as well. You can tell AsyncAF to process promises in series within the next method invocation by setting a flag with `series` or its alias `io` (in order). See the documentation for <a href="https://async-af.js.org/AsyncAF#series" target=_blank>`series`</a> for a full list of methods this works on.
163
164In some cases, the time it takes to resolve an AsyncAF expression won't differ; for example:
165
166```js
167import AsyncAF, {logAF} from 'async-af';
168import delay from 'delay';
169
170logAF.options({label: false});
171
172const bools = [
173 () => delay(3000, {value: true}),
174 () => delay(2000, {value: false}),
175 () => delay(1000, {value: false}),
176];
177
178logAF('parallel', AsyncAF(bools).someAF(n => n()));
179logAF('series', AsyncAF(bools).series.someAF(n => n()));
180
181// series true
182// in 3.000 secs
183// parallel true
184// in 3.000 secs
185```
186
187Other times, processing promises in parallel will be faster:
188
189```js
190const bools = [
191 () => delay(3000, {value: false}),
192 () => delay(2000, {value: true}),
193 () => delay(1000, {value: false}),
194];
195
196logAF('parallel', AsyncAF(bools).someAF(n => n()));
197logAF('series', AsyncAF(bools).series.someAF(n => n()));
198
199// parallel true
200// in 3.000 secs
201// series true
202// in 5.000 secs
203```
204
205And yet other times, processing promises in series will be faster:
206
207```js
208const bools = [
209 () => delay(3000, {value: true}),
210 () => delay(4000, {value: false}),
211 () => delay(5000, {value: false}),
212];
213
214logAF('parallel', AsyncAF(bools).someAF(n => n()));
215logAF('series', AsyncAF(bools).series.someAF(n => n()));
216
217// series true
218// in 3.000 secs
219// parallel true
220// in 5.000 secs
221```
222
223Being cognizant of when to use `series` vs. when to rely on the default parallel behavior can help increase the performance of your asynchronous code.
224
225Another use case for `series` might be if you're sending multiple requests to a rate-limited API. In that case you may not want to throw a ton of parallel requests at the API, but rather wait for each one in series.
226
227<div>Love AsyncAF? <a href="https://github.com/AsyncAF/AsyncAF"><img src="https://badgen.net/badge//star/blue?icon=github" alt="star it on GitHub"></a></div>
228
229See something to improve? [File an issue](https://github.com/AsyncAF/AsyncAF/issues) or
230[see how to contribute](https://github.com/AsyncAF/AsyncAF/blob/master/CONTRIBUTING.md).💙
231
232## License
233AsyncAF is licensed under the <a href="https://choosealicense.com/licenses/mit/" target=_blank>MIT License</a>, so you can pretty much use it however you want
234
235(but [click here](https://github.com/AsyncAF/AsyncAF/blob/master/LICENSE) or <a href="https://app.fossa.io/projects/git%2Bgithub.com%2FAsyncAF%2FAsyncAF/refs/branch/master/" target=_blank>here</a> to get into specifics).
236
237<a href="https://app.fossa.io/projects/git%2Bgithub.com%2FAsyncAF%2FAsyncAF/refs/branch/master/" target=_blank><img src="https://app.fossa.io/api/projects/git%2Bgithub.com%2FAsyncAF%2FAsyncAF.svg?type=large" alt="FOSSA Status"></a>