Running Asynchronous JavaScript Code in Sequence with Async Waterfall - Part 1

Project Files

Click here to download the project files. Make sure to run npm install before running node main.js

Async is a JavaScript library that allows you to control the flow of asynchronous JavaScript code. In this tutorial we are going to explore the Async.waterfall method to run asynchronous functions "in-order";

First, let's set up the project:

mkdir -p ~/Desktop/async-example && cd $_ && touch main.js && npm init  

Once you are prompted with the options, just accept the defaults. Once the package.json file is created, install async:

npm i async -S  

Then open your main.js file of your project and add the following to the file:

var async = require('async');

  function (done) {
    done(null, 'Value 1');
  function (value1, done) {
    done(null, 'Value 2');
  }, function (value2, done) {
    done(null, 'done');
], function (err) {
  if (err) throw new Error(err);

You can run this with node main.js. Once you run it, you should get the following output:

Value 1  
Value 2  

Let's go over this simple code example:

The waterfall method takes two parameters:

async.waterfall([], function (err) {});  
  • The first argument is an array and the second argument is a function.

  • Using the first argument (i.e. the array) you can specify what you want to run in order.

  • Using the second argument (i.e. the function) you can catch any errors that happens in any of the steps.

Now let's explore the first argument in more detail. To define the steps that you need to run, you need to create a function for each step. For example, if you need two steps, you need to create two functions and put them in the array:

  function firstStep() {},
  function secondStep() {}
function (err) {});  

As you can see, we have defined two functions (they can be anonymous or named, it doesn't matter). The next important thing to know is the arguments passed to these "step" functions:

  function firstStep(done) {},
  function secondStep(previousResult, done) {}
function (err) {});  

Every step function takes two arguments, except the first one. The first step function only takes one argument. Using the arguments you can access the result of the previous step and also invoke the next step.

  function firstStep(done) {
    done(null, 'Value from step 1');
  function secondStep(previousResult, done) {
function (err) {});  

If you notice, we are calling the done function with two arguments: the first argument is any error that we want to pass to the next step, and the second argument is the actual result or value that we want to pass to the next step. As you can see, for now we have set error values to null, because for now we don't really care about the errors. Hopefully now it should make more sense why the first step function takes one parameter, it's because nothing has been executed before the first function, so there are no results to be passed into the first function.

To complete the example, let's add another step function and print the result from the step two function:

var async =  require('async');  
  function firstStep(done) {

    done(null, 'Value from step 1'); // <- set value to passed to step 2
  function secondStep(step1Result, done) {

    done(null, 'Value from step 2'); // <- set value to passed to step 3
  function thirdStep (step2Result, done) {

    done(null); // <- no value set for the next step.
function (err) {  
  if (err) {
    throw new Error(err);
  } else {
    console.log('No error happened in any steps, operation done!');

Once you run this (node main.js) you should get the following output:

Value from step 1  
Value from step 2  
No error happened in any steps, operation done!  

I hope you found this tutorial useful. If you want to be notified about more tutorials like this, be sure to subscribe to the mailing list