Getting Started with Promises in Nodejs

Getting Started with Promises in Nodejs

In this article, I will show how we can use Promises in Nodejs. Promises are kind of design patterns to remove the usage of unintuitive callbacks.

In this article, I will show how we can use Promises in Nodejs. Promises are kind of design patterns to remove the usage of unintuitive callbacks.

Promises are a built-in concurrency primitive that's been part of JavaScript since ES6 in 2015. The Promise class has been included in Node.js since v4.0.0. That means, unless you're on an unmaintained version of Node.js, you can use promises without any outside libraries.

Getting Started with Promises in Node.js

A promise is an object representation of a value that is being computed asynchronously. The easiest way to create a promise is using the [Promise.resolve()]( function.

// Create a promise with a pre-computed value 'Hello, World'
const promise = Promise.resolve('Hello, World!');

promise instanceof Promise; // true

The most important function for interacting with promises is the [Promise#then()]( function. To get the promise's associated value once it is done being computed, you should call .then():

// Prints "Hello, World"
promise.then(res => console.log(res));

There is no way to access a promise's value directly. In other words, the only way to "unbox" promise into the value 'Hello, World' is by calling .then().

The Technical Details of Promises

You can think of a promise as an object representation of an asynchronous operation. Technically, a promise is a state machine representing the status of an asynchronous operation. A promise can be in one of 3 states:

1) Pending. The operation is in progress.

2) Fulfilled. The operation completed successfully.

3) Rejected. The operation experienced an error.

Here's a state diagram from Mastering Async/Await that demonstrates the possible states:

Getting Started with Promises in Nodejs

Once a promise is either fulfilled or rejected, it stays fulfilled or rejected. That is why a promise that is no longer pending is called settled.

Another important detail is that, as the client of a promise-based API, you can't fulfill or reject a promise. Given a promise object, you cannot make the promise change state, even if it is pending. You can only react to what the promise does using functions like then().

Speaking of then(), let's take another look at then() given the perspective of a promise as a state machine. The first parameter to then() is a function called onFulfilled.

promise.then(function onFulfilled(res) {
  console.log(res); // 'Hello, World'

As the name onFulfilled implies, Node.js will call your onFulfilled function if your promise changes state from pending to fulfilled. If you call then() on a function that is already fulfilled, Node.js will call onFulfilled immediately.

Errors and catch()

If promise changes state from pending to fulfilled, Node.js will call your onFulfilled function. What happens if promise changes state from pending to rejected?

Turns out the .then() function takes two function parameters, onFulfilled and onRejected. Node.js calls the onRejected function if your promise changes state from pending to rejected, or if the promise is already rejected.

  function onFulfilled(res) { console.log(res); },
  function onRejected(err) { console.log(err); }

If onRejected is null or undefined, Node.js will not treat that as an error. If a promise is rejected and it doesn't have an onRejected handler, that will become an unhandled promise rejection.

Promises also have a [Promise.reject()]( function analagous to Promise.resolve(). Here's an example of using Promise.reject() with an onRejected handler.

Promise.reject(new Error('Oops!')).then(null, function onRejected(err) {
  console.log(err.message); // Oops!

The .then(null, function onRejected() {}) pattern is so common in promises that there's a helper function for it: [Promise#catch()]( The catch() function lets you add an onRejected handler without passing an onFulfilled() function.

Promise.reject(new Error('Oops!')).catch(function onRejected(err) {
  console.log(err.message); // Oops!

Chaining Promises

Promise chaining is what lets promises avoid deeply nested callbacks, also known as "callback hell", "pyramid of doom", and "banana code".

Getting Started with Promises in Nodejs

The idea of promise chaining is that if you call then() with an onFulfilled() that function returns a new promise p, then() should return a promise that is "locked in" to match the state of p.

For example:

const p1 = Promise.resolve('p1');
// The `then()` function returns a promise!
const p2 = p1.then(() => Promise.resolve('p2'));

// Prints "p2"
p2.then(res => console.log(res));

In practice, promise chaining generally looks like a list of chained .then() calls. For example:

return asyncOperation1().
  then(res => asyncOperation2(res)).
  then(res => asyncOperation3(res)).
  // If any of `asyncOperation1()` - `asyncOperation3()` rejects, Node will
  // call this `onRejected()` handler.
  catch(function onRejected(err) { console.log(err); });

Now that you've seen the basics of promise chaining, lets see how you would use promise chaining with core Node.js APIs.

Using Promises with Core Node.js APIs

Node.js 10 introduced a promise-based API for the built-in [fs]( module. That means you can read from and write to the file system using promises in Node.js.

To use the promise-based fs API, use the following syntax:

const fs = require('fs').promises; 

Now, suppose you want to read a file, replace all instances of 'foo' with 'bar', and write the file back to disk. Here's how that might look with promise chaining.

const fs = require('fs').promises;

function replace(filename) {
  let handle;
  let contents;
  // Open a file handle
  return, 'r+').
    then(_handle => {
      handle = _handle;
      // Read the contents of the file
      return handle.readFile();
    // Replace instances of 'foo' with 'bar' in the contents
    then(_contents => {
      contents = _contents.toString().replace(/foo/g, 'bar');
    // Empty out the file
    then(() => handle.truncate()).
    // Write the replaced contents to the file
    then(() => handle.writeFile(contents)).
    then(() => console.log('done')).
    // If any step fails, this `onRejected()` handler will get called.
    catch(err => console.log(err));

Converting Callbacks to Promises

Many older Node.js APIs are still written using callbacks. Node.js has a [promisify()]( function that can convert a function that uses Node.js' callback syntax to a function that returns a promise.

const util = require('util');

function usingCallback(callback) {
  // Call `callback()` after 50 ms
  setTimeout(() => callback(null, 'Hello, World'), 50);

const usingPromise = util.promisify(usingCallback);

// Prints "Hello, World" after 50ms.
usingPromise().then(res => console.log(res));

Angular 9 Tutorial: Learn to Build a CRUD Angular App Quickly

What's new in Bootstrap 5 and when Bootstrap 5 release date?

Brave, Chrome, Firefox, Opera or Edge: Which is Better and Faster?

How to Build Progressive Web Apps (PWA) using Angular 9

What is new features in Javascript ES2020 ECMAScript 2020

Top Node.js Development Companies and Expert NodeJS Developers

A thoroughly researched list of top NodeJS development companies with ratings & reviews to help hire the best Node.JS developers who provide development services and solutions across the world. List of Leading Node.js development Service Providers...

Top Vue.js Developers in USA

Vue.js is an extensively popular JavaScript framework with which you can create powerful as well as interactive interfaces. Vue.js is the best framework when it comes to building a single web and mobile apps.

Hire Node JS Developer from Expert Node JS Development Company

NodeJS Development Company-Hire Node JS developer from the most prominent NodeJS development company, Mobiweb and get remarkable Node.js app development services.