Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replacing callbacks with promises in Node.js

I have a simple node module which connects to a database and has several functions to receive data, for example this function:


dbConnection.js:

import mysql from 'mysql';  const connection = mysql.createConnection({   host: 'localhost',   user: 'user',   password: 'password',   database: 'db' });  export default {   getUsers(callback) {     connection.connect(() => {       connection.query('SELECT * FROM Users', (err, result) => {         if (!err){           callback(result);         }       });     });   } }; 

The module would be called this way from a different node module:


app.js:

import dbCon from './dbConnection.js';  dbCon.getUsers(console.log); 

I would like to use promises instead of callbacks in order to return the data. So far I've read about nested promises in the following thread: Writing Clean Code With Nested Promises, but I couldn't find any solution that is simple enough for this use case. What would be the correct way to return result using a promise?

like image 666
Lior Erez Avatar asked Feb 10 '15 13:02

Lior Erez


People also ask

How do I change my callback to promise?

If the callback function returns non-error output, we resolve the Promise with the output. Let's start by converting a callback to a promise for a function that accepts a fixed number of parameters: const fs = require('fs'); const readFile = (fileName, encoding) => { return new Promise((resolve, reject) => { fs.

Why promises is used instead of callbacks?

They can handle multiple asynchronous operations easily and provide better error handling than callbacks and events. In other words also, we may say that, promises are the ideal choice for handling multiple callbacks at the same time, thus avoiding the undesired callback hell situation.

What is the difference between callback and promise in Nodejs?

Callbacks are functions passed as arguments into other functions to make sure mandatory variables are available within the callback-function's scope. Promises are placeholder objects for data that's available in the future.


1 Answers

Using the Promise class

I recommend to take a look at MDN's Promise docs which offer a good starting point for using Promises. Alternatively, I am sure there are many tutorials available online.:)

Note: Modern browsers already support ECMAScript 6 specification of Promises (see the MDN docs linked above) and I assume that you want to use the native implementation, without 3rd party libraries.

As for an actual example...

The basic principle works like this:

  1. Your API is called
  2. You create a new Promise object, this object takes a single function as constructor parameter
  3. Your provided function is called by the underlying implementation and the function is given two functions - resolve and reject
  4. Once you do your logic, you call one of these to either fullfill the Promise or reject it with an error

This might seem like a lot so here is an actual example.

exports.getUsers = function getUsers () {   // Return the Promise right away, unless you really need to   // do something before you create a new Promise, but usually   // this can go into the function below   return new Promise((resolve, reject) => {     // reject and resolve are functions provided by the Promise     // implementation. Call only one of them.      // Do your logic here - you can do WTF you want.:)     connection.query('SELECT * FROM Users', (err, result) => {       // PS. Fail fast! Handle errors first, then move to the       // important stuff (that's a good practice at least)       if (err) {         // Reject the Promise with an error         return reject(err)       }        // Resolve (or fulfill) the promise with data       return resolve(result)     })   }) }  // Usage: exports.getUsers()  // Returns a Promise!   .then(users => {     // Do stuff with users   })   .catch(err => {     // handle errors   }) 

Using the async/await language feature (Node.js >=7.6)

In Node.js 7.6, the v8 JavaScript compiler was upgraded with async/await support. You can now declare functions as being async, which means they automatically return a Promise which is resolved when the async function completes execution. Inside this function, you can use the await keyword to wait until another Promise resolves.

Here is an example:

exports.getUsers = async function getUsers() {   // We are in an async function - this will return Promise   // no matter what.    // We can interact with other functions which return a   // Promise very easily:   const result = await connection.query('select * from users')    // Interacting with callback-based APIs is a bit more   // complicated but still very easy:   const result2 = await new Promise((resolve, reject) => {     connection.query('select * from users', (err, res) => {       return void err ? reject(err) : resolve(res)     })   })   // Returning a value will cause the promise to be resolved   // with that value   return result } 
like image 131
Robert Rossmann Avatar answered Sep 24 '22 05:09

Robert Rossmann