How do I convert this code using promises?

2019-09-11 05:51发布

问题:

I am new to Nodejs.I want to convert this code to promises (nodejs).This includes four callback function get(),abc1(),pqr(),xyz(). It gives error of "cannot read property 'then' of undefined" Can anyone fix it? I am trying it to convert into promises from this example here

var jwt = require('jwt-simple');
var mysql = require('mysql');
var async = require('async');
var Promise = require('bluebird');

var connection = mysql.createConnection({
    host: 'localhost',
    port: 3306,
    database: 'abc',
    user: 'root',
    password: ''
});


var auth = {
    login: function (req, res) {
        var username = req.body.username || '';
        var password = req.body.password || '';
        console.log(req.body);
        //This is get() function 
        function get(err, rows) {
            connection.connect(function (err) {
                if (err) {
                    console.error('error connecting: ' + err.stack);
                    return;
                } else {
                    console.log("connected to database");
                    connection.query("SELECT count(id) as count from abc where name=? AND email=?", [username, password], function (err, rows) {
                        if (err) {
                            throw err
                        } else {

                            b = rows;
                            console.log(b);
                        }
                    });
                }
            });
        }

        //this is abc1() function                
        function abc1(err, rows) {
            console.log("onresult");
            if (err) {
                throw err;
                console.log("error in Query");
            } else {
                if (rows[0].count != 1) {
                    //xyz(result,xyz);
                    res.json({
                        "status": 401,
                        "message": "Invalid credentials"
                    });
                } else {
                    connection.query("SELECT email from abc where name=? AND email=?", [username, password], function (err, rows) {});
                    //res.json(genToken("ayush"));
                }
            }
        }
        //This is xyz() function
        function xyz(err, rows) {
            if (err) {
                console.log(err);
            }
            console.log(rows);
            connection.query("SELECT name from abc where name=? AND email=?", [username, password], function (err, rows) {});
        }
        //This is pqr() Function    
        function pqr(err, rows) {
            if (err) {
                console.log(err);
            }
            console.log(rows);
        }
        get()
            .then(function (rows) {
                // do something...
                //console.log("hellow1");
                return abc1();
            })
            .then(function (rows) {
                // do something...  
                console.log("hellow2");
                return xyz();
            })
            .then(function (rows) {
                // the third and final async response
                console.log("hellow3");
                return pqr();
            })
            .then(function (rows) {
                // the third and final async response
                console.log("hellow4");
            })
            .fail(function (err) {
                // handle any error resulting from any of the above calls 
                throw err;
            })
            .done();
    }
}

回答1:

With arguments (err, rows), all four functions appear to be written as nodebacks and we can make a shrewd guess as to what the original working code looked like.

Without modification, nodebacks can only be used as nodebacks. Inserting them raw into a promise chain won't work.

But your functions will work in a promise chain after :

  • Promisifying the underlying asycn functions, ie connection's methods.
  • Calling, in the functions, the connection.methodAsync() version of the methods instead of connection.method().
  • Returning a promise from each of your functions.

The whole thing actually works better with a little renaming/refactoring to start with a connect() function rather than get().

var jwt = require('jwt-simple');
var mysql = require('mysql');
var async = require('async');
var Promise = require('bluebird');

var connection = mysql.createConnection({
    host: 'localhost',
    port: 3306,
    database: 'abc',
    user: 'root',
    password: ''
});

//Promisify `connection`. 
//Lucky you, Bluebird has a `.promisifyAll()` method.
Promise.promisifyAll(connection);

//Now, `auth` will be something like this :
var auth = {
    login: function (req, res) {
        var username = req.body.username || '';
        var password = req.body.password || '';

        //Let's assume you want to build an object containing various user details
        var authObj = {
            'userName': userName,
            'email': null, //to be set later
            'name': null //to be set later
        };

        function connect() {
            return connection.connectAsync().catch(function(err) {
                throw 'Error connecting: ' + err.stack;
            });
        }

        function abc1() {
            return connection.queryAsync("SELECT count(id) as count from abc where name=? AND email=?", [username, password]).then(function (rows) {
                if (rows[0].count != 1) {
                    throw new Error('Invalid credentials');
                }
            });
        }

        function xyz() {
            return connection.queryAsync("SELECT email from abc where name=? AND email=?", [username, password]).then(function(rows) {
                return rows[0].email;
            });
        }

        function pqr() {
            return connection.queryAsync("SELECT name from abc where name=? AND email=?", [username, password]).then(function(rows) {
                return rows[0].name;
            });
        }

        return connect()
        .then(abc1)//check credentials
        .then(xyz)//get email
        .then(function (email) {
            authObj.email = email;
            return pqr();//get name
        })
        .then(function (name) {
            authObj.name = name;
            return authObj;//make authObj available to auth.login()'s caller.
        })
        .catch(function (err) {
            // handle any error resulting from any of the above calls.
            console.log(err);
            throw err;//make the error available to auth.login()'s caller.
        });
    }
}

As you will see, err doesn't feature in the code until the bottom of auth.login(). It is the nature of promisified nodebacks that errors propagate down the promise chain's error path, and don't need to be handled mid-chain unless you need to do something like mid-chain error recovery.

Whereas this is good for learning how to construct a promise chain, in practice you appear already to know name and email at the outset, and you would probably choose to login and obtain other user details in one hit with suitable SQL.