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

v2.0.0

Published

Iterate over async code with a for-loop like syntax

Downloads

11

Readme

async-for

Builds a function which lets asynchronous functions run with a for loop like syntax. The function does not store state and may be reused from multiple asynchronous computations simultaneously, and can load data for loop invocations without having to create the loop in a closure. The created loops check for a range of error conditions, such as a missing callback or exiting the loop multiple times, and throws descriptive errors in these cases. By default the loop spreads iterations across the event loop using setImmediate() and thus can iterate indefinitely without overflowing the stack.

Installation

npm install async-for

A brief example

Here is a contrived loop which uses two synchronous functions:

for(var i = 0; i < 10; i++) { 
  var result = doSomeSynchronousCoputationHere(i);
  if (result.skipIteration) continue;
  if (result.isComplete) break;
  doMoreSynchronousComputationHere();
}

Here is the equivalent loop in which the functions are asynchronous:

var _for = require('asyncFor');

var loop = _for(0, function (i) { return i < 10; }, function (i) { return i + 1; },
  function loopBody(i, _break, _continue) {
    doSomeAsynchronousComputationHere(i, function callback (result) {
      if (result.skipIteration) return void _continue();
      if (result.isComplete) return void _break();
      doMorAsynchronousComputationHere(_continue);
    });
  }));
  
loop(callbackFunctionGoesHere);

Overview

async-for takes four arguments:

  • The initial value of the iteration variable. This may be any type, not just a number. Equivalent to the var i = 0; section of a for loop.
  • The check clause. This is a function which takes one argument and returns a boolean. At the end of each iteration this function will be passed the current value of the iteration variable. If the function returns false, iteration stops. Equivalent to the i < max; section of a for loop.
  • The increment clause. This is a function which takes one argument and returns one value. At the end of each iteration the current value of the iteration variable will be passed to this function, and the iteration variable will be set to the return value of this function for the next iteration. Equivalent to the i++; section of a for loop
  • The loop body. This is a function which takes three arguments: i, _break, and _continue

The wrapped function is passed the arguments (i, _break, _continue, data). To end looping call return void _break(). To move to the next iteration call return void _continue(). _continue may be passed as a callback to asynchronous functions in the body. data holds whatever was passed to the loop function at invocation time, as described below.

If the loop is expected to count from zero to a finishing number by one each step, everything but the limit and function body may be omitted:

var loop = _for(10, loopBodyFunction);
//Equivalent to var loop = _for(0, function (i) { return i < 10; }, function (i) { return i + 1; }, loopBodyFunction)

loop(callback);

Data may be passed to the loop function along with the callback, and will be provided to every iteration of the loop

var loop = _for(10, function body (i, _break, _continue, data) {
  someAsyncFunction(data, _continue);
});

loop({ sampleData: 'to operate on' }, callback);

A value may be returned from the loop by passing it to _break

var loop = _for (10, function (i, _break) {
  if (i === 5) return void _break (i);
});

loop (function (returnValue) {
  // returnValue === 5
});

Asynchronicity

To avoid stack overflows when performing a high number of iterations when given a synchronous loop body, iterations are spread across event loop ticks by using setImmediate() every time _continue is called. If this behavior is not desired, use var _for = require('async-for').sync; instead of var _for = require('async-for');

Errors and debugging

To avoid silent errors, created loops will throw errors when cases occur that indicate a programming error, and which could lead to difficult-to-debug behavior. These cases are:

  • If both _break and _continue are called in the same iteration of a loop
  • If _continue is called multiple times in the same iteration of a loop
  • If a loop is invoked without providing a callback or operating in fire-and-forget mode (explained below) If this behaviour is not desired, loops can be created in unsafe mode by using var _for = require('async-for').unsafe; instead of var _for = require('async-for');, but this is highly unrecommended.

If a loop should be run without a callback, it can be invoked as so:

var loop = _for(10, someBodyFunction);
loop.fireAndForget();

For ease of debugging, loops may be given names, which will be included in error messages in the case of an error:

var loop = _for(10, someBodyFunction);
var loopWithName = loop.named('Susan');
loopWithName(data, callback);

loop.named('Bob').fireAndForget() will behave as expected.

License

MIT