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-af

v7.0.39

Published

The asynciest of async libs there ever was or ever will be...AsyncAF!?

Downloads

611

Readme

Working with promises or async/await?

Use 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.

Usage

const AsyncAF = require('async-af');

function getActiveUsers(userIds) {
  return AsyncAF(userIds)
    // map user ids to user objects with an async function
    .mapAF(async userId => {
      const user = await fetch(`fake-game-api/users/${userId}`);
      return user.json();
    })
    // filter by active users
    .filterAF(user => user.isActive);
}

AsyncAF methods are await-able and then-able.

async function sendMsgToActiveUsers(msg) {
  const activeUsers = await getActiveUsers([1, 2, 3]);
  // send each active user a msg in series
  await AsyncAF(activeUsers).series.forEachAF(async ({id}) => {
    await sendMsg(id, msg); // hypothetical msg service that's rate-limited
  });
  console.log('message sent!');
}

function doSomethingElseWithActiveUsers() {
  return getActiveUsers([1, 2, 3]).then(activeUsers => {
    // ... do something else
  });
}

If a Promise is passed into AsyncAF, it will be settled before a method processes it.

const userMsg = Promise.resolve('I\'m [restricted word] AF right now')

const msgContainsBadWord = (msg, word = '[restricted word]') => AsyncAF(msg).includesAF(word);

msgContainsBadWord(userMsg); // resolves to true

Array methods will settle any promises in an array before processing them.

const findHighScoringUser = () => AsyncAF([
  fetch('fake-game-api/users/1').then(user => user.json()), // {id: 1, name: Aiden, score: 9001, ...}
  {id: 2, name: 'Bill', score: 3600, /* ... */},
  {id: 3, name: 'Cari', score: 5800, /* ... */},
])
  .findAF(({score}) => score > 9000);

findHighScoringUser(); // resolves to {id: 1, name: Aiden, score: 9001, ...}

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.

For example:

const promises = [1, 2, 3].map(n => Promise.resolve(n));

AsyncAF(promises).map(n => n * 2).filter(n => n !== 4).forEach(n => console.log(n));
// or
AsyncAF(promises).mapAF(n => n * 2).filterAF(n => n !== 4).forEachAF(n => console.log(n));
// both log 2 then 6

Installation 💾

Easy peasy, just

$ npm install --save async-af,

right?

⚠️ Not so fast; there's actually several ways to include AsyncAF in your project/production site from easy to more complex:

🔸 yarn: $ yarn add async-af

🔹 bower: async-af is no longer published to bower. To continue using it with bower, look into bower-npm-resolver.

🔸 cdn: See the table for which script tag to use:

🔹 scoped packages:

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, @async-af/map and/or @async-af/filter; see further instructions in the documentation for AsyncAfWrapper and AsyncAfWrapper.use.

🔸 scoped packages + babel-plugin-transform-imports:

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 babel-plugin-transform-imports and condense that ugly wall down to a single import statement! See Wrapper/Use: Too Many 🤬 Imports!? for a tutorial.

🔹 es modules:

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.

Using the cdn scripts as an example:

or minimized for production:

The script with <script type="module"> will load in any browser capable of loading es modules, while the script with <script nomodule> will act as a fallback for legacy browsers.

See here and here for further reading on this strategy.

A couple notes on performance 🚀

Built on Promises

Despite 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 results in some loooong code due to pulling in things like Facebook's regenerator and others to make it work.

Because 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.

Use series wisely

The 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 series for a full list of methods this works on.

In some cases, the time it takes to resolve an AsyncAF expression won't differ; for example:

import AsyncAF, {logAF} from 'async-af';
import delay from 'delay';

logAF.options({label: false});

const bools = [
  () => delay(3000, {value: true}),
  () => delay(2000, {value: false}),
  () => delay(1000, {value: false}),
];

logAF('parallel', AsyncAF(bools).someAF(n => n()));
logAF('series', AsyncAF(bools).series.someAF(n => n()));

// series true
// in 3.000 secs
// parallel true
// in 3.000 secs

Other times, processing promises in parallel will be faster:

const bools = [
  () => delay(3000, {value: false}),
  () => delay(2000, {value: true}),
  () => delay(1000, {value: false}),
];

logAF('parallel', AsyncAF(bools).someAF(n => n()));
logAF('series', AsyncAF(bools).series.someAF(n => n()));

// parallel true
// in 3.000 secs
// series true
// in 5.000 secs

And yet other times, processing promises in series will be faster:

const bools = [
  () => delay(3000, {value: true}),
  () => delay(4000, {value: false}),
  () => delay(5000, {value: false}),
];

logAF('parallel', AsyncAF(bools).someAF(n => n()));
logAF('series', AsyncAF(bools).series.someAF(n => n()));

// series true
// in 3.000 secs
// parallel true
// in 5.000 secs

Being cognizant of when to use series vs. when to rely on the default parallel behavior can help increase the performance of your asynchronous code.

Another 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.

See something to improve? File an issue or see how to contribute.💙

License

AsyncAF is licensed under the MIT License, so you can pretty much use it however you want

(but click here or here to get into specifics).