How to convert a callback in Node. js to Promise

  • 2021-09-16 06:03:51
  • OfStack

Preface

A few years ago, callbacks were the only way to implement asynchronous code execution in JavaScript. There is almost nothing wrong with the callback itself, and the most notable thing is "callback hell".

Promise is introduced in ES6 as a solution to these problems. Finally, the async/await keyword is introduced to provide a better experience and improve readability.

Even with the new method, there are still many native modules and libraries that use callbacks. In this article, we will discuss how to convert an JavaScript callback to an Promise. The knowledge of ES 6 will come in handy because we will use functions such as the expansion operator to simplify things.

What is a callback

A callback is a function argument, which happens to be a function itself. Although we can create any function to accept another function, callbacks are mainly used for asynchronous operations.

JavaScript is an interpretive language that can handle only one line of code at a time. Some tasks may take a long time to complete, such as downloading or reading large files. JavaScript moves these long-running tasks to browsers or other processes in the Node. js environment. So that it does not prevent the execution of other code.

Usually asynchronous functions accept callback functions, so they can process their data after completion.

For example, we will write a callback function that will be executed after the program successfully reads the file from the hard disk.

So you need to prepare a text file named sample. txt that contains the following:


Hello world from sample.txt

Then write a simple Node. js script to read the file:


const fs = require('fs');

fs.readFile('./sample.txt', 'utf-8', (err, data) => {
  if (err) {
    //  Handling errors 
    console.error(err);
     return;
  }
  console.log(data);
});

for (let i = 0; i < 10; i++) {
  console.log(i);
}

After running the code, it will output:

0
...
8
9
Hello world from sample.txt

If this is the code, you should see 0. 9 output to the console before executing the callback. This is due to the asynchronous management mechanism of JavaScript. After reading the file, the callback that outputs the contents of the file is called.

Incidentally, callbacks can also be used in synchronization methods. For example, Array. sort () accepts a callback function that allows you to customize how elements are sorted.

® Functions that accept callbacks are called "higher-order functions." In fact, in fact, the

Now we have a better callback method. Then let's continue to see what Promise is.

What is Promise

Promise was introduced in ECMAScript 2015 (ES6) to improve the experience of asynchronous programming. As the name implies, the "value" or "error" that the JavaScript object will eventually return should be 1 Promise.

1 Promise has 3 states:

Pending (pending): Used to indicate the initial state that an asynchronous operation has not been completed. Fulfilled (Completed): Indicates that the asynchronous operation completed successfully. Rejected (rejected): Indicates that the asynchronous operation failed.

Most Promise end up looking like this:


someAsynchronousFunction()
  .then(data => {
    // promise  Be completed 
    console.log(data);
  })
  .catch(err => {
    // promise  Be rejected 
    console.error(err);
  });

Promise is very important in modern JavaScript because they are used with the async/await keyword 1 introduced in ECMAScript 2016. Using async/await eliminates the need to write asynchronous code with callbacks or then () and catch ().

If you want to rewrite the previous example, it should be like this:


try {
  const data = await someAsynchronousFunction();
} catch(err) {
  // promise  Be rejected 
  console.error(err);
}

This looks like a "1-like" synchronous JavaScript. Most popular JavaScript libraries and new projects use the Promises and async/await keywords together.

However, if you want to update existing libraries or encounter old code, you may be interested in migrating callback-based API to Promise-based API, which can improve your development experience.

Look at several ways to convert callbacks to Promise under 1.

Convert callback to Promise

Node.js Promise

Most asynchronous functions that accept callbacks in Node. js, such as the fs module, have a standard implementation by passing the callback as the last argument.

For example, this is a way to read a file with fs. readFile () without specifying a text encoding:


fs.readFile('./sample.txt', (err, data) => {
  if (err) {
    console.error(err);
     return;
  }
  console.log(data);
});

Note: If you specify utf-8 as the encoding, the output is a string. If you do not specify that the resulting output is Buffer.

In addition, the callback passed to this function should accept Error because it is the first parameter. You can then have any number of outputs.

If the function you need to convert to Promise follows these rules, you can use util. promisify, a native Node. js module that contains callbacks to Promise.

First import the QUANGES 148EN ` module:


const util = require('util');

It is then converted to Promise using the promisify method:


const fs = require('fs');
const readFile = util.promisify(fs.readFile);

Now, use the newly created function as promise:


readFile('./sample.txt', 'utf-8')
  .then(data => {
    console.log(data);
  })
  .catch(err => {
    console.log(err);
  });

Alternatively, you can use the async/await keywords given in the following example:


const fs = require('fs');
const util = require('util');

const readFile = util.promisify(fs.readFile);

(async () => {
  try {
    const content = await readFile('./sample.txt', 'utf-8');
    console.log(content);
  } catch (err) {
    console.error(err);
  }
})();

You can only use the await keyword in functions created with async, which is why function wrappers are used. Function wrappers are also called function expressions that are called immediately.

Don't worry if your callback doesn't follow this specific standard. The util. promisify () function allows you to customize how the conversion occurs.

Note: Promise became popular shortly after its introduction. Node. js has converted most of the core functions from callbacks to API based on Promise.

If you need to process files with Promise, you can use the library that comes with Node. js (https://nodejs. org/docs/latest-v10.x/api/fs. html # fs_fs_promises_api).

Now you know how to imply the Node. js standard style callback into Promise. Beginning with Node. js 8, this module is only available on Node. js. If you are using a browser or an earlier version of Node, it is best to create your own version of the function based on Promise.

Create your own Promise

Let's discuss how to turn the callback to util. promisify () function promise in 1.

The idea is to create a new Promise object with callback functions. If the callback function returns an error, the Promise with the error is rejected. If the callback function returns a non-error output, it resolves and outputs Promise.

Start by converting the callback to an promise of a function that accepts a fixed argument:


const fs = require('fs');

const readFile = (fileName, encoding) => {
  return new Promise((resolve, reject) => {
    fs.readFile(fileName, encoding, (err, data) => {
      if (err) {
        return reject(err);
      }

      resolve(data);
    });
  });
}

readFile('./sample.txt')
  .then(data => {
    console.log(data);
  })
  .catch(err => {
    console.log(err);
  });

The new function readFile () accepts two arguments to read the fs. readFile () file. Then create a new Promise object that wraps the function and accepts a callback, in this case fs. readFile ().

reject Promise instead of returning an error. So the code does not immediately output the data, but first resolve Promise. Then use the readFile () function based on Promise as before.

Next, look at the function that accepts dynamic quantity parameters:


const fs = require('fs');

fs.readFile('./sample.txt', 'utf-8', (err, data) => {
  if (err) {
    //  Handling errors 
    console.error(err);
     return;
  }
  console.log(data);
});

for (let i = 0; i < 10; i++) {
  console.log(i);
}

0

The first parameter is the callback parameter, which makes it a bit different in functions that accept callbacks.

The way to convert to promise is the same as the previous example. Create a new Promise object that wraps functions that use callbacks. If an error is encountered, it will be reject, and when the result appears, it will be resolve.

Our promise version is as follows:


const fs = require('fs');

fs.readFile('./sample.txt', 'utf-8', (err, data) => {
  if (err) {
    //  Handling errors 
    console.error(err);
     return;
  }
  console.log(data);
});

for (let i = 0; i < 10; i++) {
  console.log(i);
}

1

When creating an promise, it doesn't matter whether the function uses a callback in a nonstandard way or with many parameters. We can completely control how it is completed, and the principle is one.

Although callbacks are now the default method for leveraging asynchronous code in JavaScript, Promise is a more modern method that is easier to use. If you encounter a code base that uses callbacks, you can now convert it to Promise.

In this article, we first learned how to use the utils. promisfy () method in Node. js to convert a function that accepts a callback to Promise. Then, you learned how to create your own Promise object and wrap functions in the object that accept callbacks without using an external library. So much of the old JavaScript code can be easily blended with the modern code base and mixed in 1.

Summarize


Related articles: