Iterate[.md]

iterate is a utility function that allows for execution of asynchronous code in the iteratee, waiting for each iteration to finish before moving on. This was inspired by the plugin interface of the Node.js server framework Hapi. Hapi plugins historically had the following structure:

function myPlugin(server, options, next) {
  doSomethingAsynchronous(() => {
    next();
  });
}

The next plugin in the queue won't be registered until the preceding plugin calls next(). My goal was to implement a similar functionality for arrays, like forEach, but with an extra next parameter passed to the iteratee.

Implementation

function iterate(arr, iteratee, fn) {
  (function step(i) {
    if (i in arr) {
      iteratee(arr[i], i, arr, () => {
        step(i + 1);
      });
    } else {
      fn();
    }
  })(0);
}

Example:

const arr = ['foo', 'bar', 'baz'];

console.log('start');

iterate(arr, (item, i, arr, next) => {
  setTimeout(() => {
    console.log(item);
    next();
  }, 1000);
}, () => {
  console.log('finish');
});
> 0s (+0s) "start"
> 1s (+1s) "foo"
> 2s (+1s) "bar"
> 3s (+1s) "baz"
> 3s (+0s) "finish"

Update 2020

Of course nowadays with the current Ecmascript spec, you could just pair for...of and async functions to accomplish the same thing:

async () => {
  for (const item of items) {
    await doSomethingAsynchronous(item);
  }
};

Comments