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

runnel

v0.5.3

Published

Simple and small flow control library to execute async functions in sequence

Downloads

15,844

Readme

runnel Build Status

testling badge

run·nel/ˈrənl/ - A narrow channel in the ground for liquid to flow through.

Simple and small (~ 80 loc) flow control library to execute async functions in sequence.

Table of Contents generated with DocToc

Installation

npm install runnel

Examples

Parameter passing

var runnel = require('runnel');

function uno (cb) {
  setTimeout(function () { cb(null, 'eins'); } , 100);
}

function dos (resuno, cb) {
  setTimeout(function () { cb(null, resuno, 'zwei'); } , 100);
}

function tres (resuno, resdos, cb) {
  setTimeout(function () { cb(null, resuno, resdos, 'drei'); } , 100);
}

runnel(
    uno
  , dos
  , tres 
  , function done(err, resuno, resdos, restres) {
      if (err) return console.error('Error: ', err);
      console.log('Success: uno: %s, dos: %s, tres: %s', resuno, resdos, restres);
    }
);

// => Success: uno: eins, dos: zwei, tres: drei

Passing Array of functions

// using uno, dos, tres and done functions from above

var funcs = [uno, dos, tres ];
funcs.push(done);

runnel(funcs);

Seeding a start value

function size (file, acc, cb) {
  var p = path.join(__dirname, '..', file);

  fs.stat(p, function (err, stat) {
    if (err) return cb(err);

    acc[file] = stat.size;
    cb(null, acc);
  });
}

runnel(
    // {} will be passed as the first value to next function 
    // and thus become 'acc', the accumulator
    runnel.seed({})
  
    // after we bind 'file' to the size function the resulting 
    // custom size function has signature 'function (acc, cb) {}'
  , size.bind(null, '.gitignore')
  , size.bind(null, '.jshintrc')
  , size.bind(null, '.travis.yml')

  , function done (err, acc) {
      if (err) return console.error(err);
      console.log('sizes:', acc);
    }
);

// => sizes: { '.gitignore': 96, '.jshintrc': 249, '.travis.yml': 52 }

full example

same example using array of functions

Features

  • intuitive argument passing
  • seeding a start value to enable async reduce like functionality
  • fails early
  • no magic
    • no special (ab)uses of this
    • no context passing
  • adheres to known nodejs pattern i.e., callbacks are expected to be of the form function (err[,res]*) { ... }
  • super small
  • browser support

API

All functions below are expected to invoke the callback like so:

  • cb(null, res1[, res2][,..] if no error occurred
  • cb(err) if an error occurred

runnel(fn1[, fn2][, fn3][, ...], done)

Sequentially runs all the given functions, passing results from one to the next. In case any of the functions calls back with an error done will be called with that error immediately.

runnel([fn1, fn2, .., done])

Same as above except that functions are passed as an array rather than as separate values, which allows building up a flows with array operations like concat and push like is done in this example.

More importantly it allows mapping values to async functions and then execute them sequentially, akin to Q.all.

For more information see this real world example.

runnel.seed(value)

Returns a function that will call back with the seeded value as the result, which can then be consumed by the next function in line. This allows easily implementing async reduce flows as shown in this example

Compatibility

  • commonJS compatible, so it works with nodejs and browserify
  • AMD compliant (i.e., shimlessly works with requirejs)
  • attaches itself to the window object if neither commonJS or AMD support is detected

Early failure

In order to avoid surprises runnel aborts the entire call chain once any function calls back with an error.

In that case the last function in the chain is called with the error in order to provide feedback that something went wrong.

Why another flow control library

From my experience simple, sequential flow control is sufficient in 90% of the cases and therefore using fuller featured and therefore also larger flow control libraries is unnecessary in those instances.

runnel however was designed for exactly these situations.

It helps avoid nesting callbacks and results in much more readable and maintainable code.

It also helps minimize repetitive if (err) { cb(err); return; } ... occurences.

Finally because runnel focuses only on one thing it's a very small module (~ 80 loc).

More Examples

Looky here: examples or consult the tests.

Similar libraries with larger feature set