Node.js — Run Async Functions/Promises in Sequence

Code Sample

Async functions are part of Node.js since version 7.6. They received a boost in attention with the stable release of Node.js v8 because it’s one of the major new features.

When using async functions in your projects, you may encounter situations where you want to serialize the processing. The individual functions should run asynchronously but in sequence.

This tutorial shows you two ways to run async functions or promises in sequence.

Node.js Series Overview

  1. String Replace All Appearances
  2. Remove All Whitespace From a String in JavaScript
  3. Generate a Random ID or String in Node.js or JavaScript
  4. Remove Extra Spaces From a String in JavaScript or Node.js
  5. Remove Numbers From a String in JavaScript or Node.js
  6. Get the Part Before a Character in a String in JavaScript or Node.js
  7. Get the Part After a Character in a String in JavaScript or Node.js
  8. How to Check if a Value is a String in JavaScript or Node.js
  9. Check If a String Includes All Strings in JavaScript/Node.js/TypeScript
  10. Check if a Value is a String in JavaScript and Node.js
  11. Limit and Truncate a String to a Given Length in JavaScript and Node.js
  12. Split a String into a List of Characters in JavaScript and Node.js
  13. How to Generage a UUID in Node.js
  14. Reverse a String in JavaScript or Node.js
  15. Split a String into a List of Lines in JavaScript or Node.js
  16. Split a String into a List of Words in JavaScript or Node.js
  17. Detect if a String is in camelCase Format in Javascript or Node.js
  18. Check If a String Is in Lowercase in JavaScript or Node.js
  19. Check If a String is in Uppercase in JavaScript or Node.js
  20. Get the Part After First Occurrence in a String in JavaScript or Node.js
  21. Get the Part Before First Occurrence in a String in JavaScript or Node.js
  22. Get the Part Before Last Occurrence in a String in JavaScript or Node.js
  23. Get the Part After Last Occurrence in a String in JavaScript or Node.js
  24. How to Count Words in a File
  25. How to Shuffle the Characters of a String in JavaScript or Node.js
  26. Append Characters or Words to a String in JavaScript or Node.js
  27. Check if a String is Empty in JavaScript or Node.js
  28. Ensure a String Ends with a Given Character in JavaScript or Node.js
  29. Left-Trim Characters Off a String in JavaScript or Node.js
  30. Right-Trim Characters Off a String in JavaScript or Node.js
  31. Lowercase the First Character of a String in JavaScript or Node.js
  32. Uppercase the First Character of a String in JavaScript or Node.js
  33. Prepend Characters or Words to a String in JavaScript or Node.js
  34. Check if a String is a Number
  35. Convert a String to Buffer
  36. Prevent Line Breaks in String Template Literals
  37. How to Implement a Custom `toString` Method (Coming soon)
  38. What Is `Symbol.toStringTag` and How to Use It (Coming soon)

Code Samples

You can find running code examples in the nodejs-tutorials repository on GitHub. You can run both files in the linked directory:

node index.js

# or

node with-errors.js  

Have fun!

Preparations

The examples in this tutorial simulate asynchronous processing by waiting for a period of milliseconds. This waiting time imitates the functionality you may run in your application, e.g., fetch data from the database, calling an external API, loading files from disk.

The function simulating an asynchronous request is called asyncProcessing(ms) and accepts an integer as a parameter. The parameter represents the waiting time in milliseconds:

async function asyncProcessing (ms) {  
  await new Promise(resolve => setTimeout(ms, resolve))

  console.log(`waited: ${ms}ms`)

  return ms
}

The upcoming examples use the asyncProcessing() function.

Approach 1: Run Promises in Sequence Using “for…of”

The integrated for…of loop allows you to run promises or async functions in sequence. it iterates through a list of items and you can then await the async function:

async function forOf() {  
  const timeouts = [10, 600, 200, 775, 125, 990]

  for (const timeout of timeouts) {
    result.push(await asyncProcessing(timeout))
  }

  return result
}


async function asyncProcessing (ms) {  
  await new Promise(resolve => setTimeout(ms, resolve))

  console.log(`waited: ${ms}ms`)

  return ms
}

The example above takes each item from the timeouts array and passes it as a parameter to the asyncProcessing function. While in the loop, you must await the individual function calls to serialize them.

Approach 2: Run Promises in Sequence using “Array.reduce()”

You may know Array.reduce() to run an action on each item in the list and also carry through the result of the previous processing.

Combining the benefits of reducing an array and running asynchronous operations allows you to streamline the processing. The gimmick here: you must await the call of asyncProcessing and also the carry.

In this example, the carry variable represents the accumulator. The async callback function returns a promise and this promise will be passed as the accumulator on the next item:

const timeouts = [10, 600, 200, 775, 125, 990]

async function reduce() {  
  const result = await timeouts.reduce(async (carry, timeout) => {
    return [
      …(await carry),
      await asyncProcessing(timeout)
    ]
  }, Promise.resolve([]))
}


async function asyncProcessing (ms) {  
  await new Promise(resolve => setTimeout(ms, resolve))

  console.log(`waited: ${ms}ms`)

  return ms
}

Please notice that you must also await the .reduce(). The final return value will be a promise and you must await it to retrieve the result.

Decide which handling you like more and enjoy serializing async functions in your application!

Error Handling

When running a list of asynchronous functions in sequence and one of the functions fails, the processing will stop at the failing item. The remaining items in the list won’t be touched if you don’t have proper error handling in place.

Both code examples above are optimistic implementations. There’s no try/catch block to catch any error and handle it. Ensure that you’re not blowing up your app by skipping the error handling.


Mentioned Resources

Explore the Library

Find interesting tutorials and solutions for your problems.