Node.js/Async - How to avoid callback hell with async?

前端 未结 3 1926
一生所求
一生所求 2021-01-12 04:55

I\'m new to Node.Js and JavaScript web development on the backend. I see that callbacks inside callbacks could be a pain and there are modules to avoid that. One of these mo

3条回答
  •  隐瞒了意图╮
    2021-01-12 05:26

    Here is the code modified to use async whenever needed.

    function check_auth_user(username, password) {
        var client = new pg.Client("pg://user:pass@127.0.0.1/database");
        async.waterfall([
          client.connect,
          function(callback) {
            client.query('select * from "user" where username = $1 and password = $2', [username, password], callback);
          },
          function(result, callback) {
            if(result.rowCount > 0) {
                    var res = result.rows[0];
    
                    async.series([
                       function(callback) {
                         passport.serializeUser(res, function(res, done) {
                           callback(null, res);
                         }
                       },
                       function(res, callback){
                         if(res) {
                           passport.deserializeUser(res, function(res, done) {
                              callback(null, res);
                           });
                         } else {
                           callback(new Error('SerializeUser failed'));
                         }
                       }
                    ], function(err, res) {
                        if(err) {
                           callback(err);
                        } else {
                           callback(null);
                        }
                    });
            }
            else {
               callback(new Error("No result"));
            }
          }
        ], function(err, result) {
           if(err)
              console.err(err);
        });
    }
    

    Obviously, it does not make the code any more readable. I would suggest additional changes:

    • Querying the database should be separated in its own method (it is indeed a model method), thus allowing error checking to happen in its own "dominion".
    • Passport serialization/deserialization should be done in a separate method, for the same reasons.

    These two methods would both take callbacks. Here is a re-write:

    // Given a client, queries for user
    function retrieveUser( client, username, password, cb) {
      client.query('select * from "user" where username = $1 and password = $2', [username, password], function(err, users){
        if(err) {
          cb(err);
        }
        else if(users.rowCount < 0) {
          cb(new Error("No user found for username ="+username));
        }
        else {
          cb(null, result.rows[0]);
      });
    }
    
    //Uses passport to serialize/deserializeUser
    function passportSerialize(user, cb){
          async.series([
           function(callback) {
             passport.serializeUser(user, function(res, done) {
               callback(null, res);
             }
           },
           function(res, callback){
             if(res) {
               passport.deserializeUser(res, function(res, done) {
                  if(res) {
                     callback(null, res);
                  } else {
                     callback(new Error('deserializeUser failed'));
                  } 
               });
             } else {
               callback(new Error('SerializeUser failed'));
             }
           }
        ], cb);
    }
    

    Thus, our main method now becomes:

    function check_auth_user(username, password) {
        var client = new pg.Client("pg://user:pass@127.0.0.1/database");
        async.waterfall([
          client.connect,
          function(callback) {
            retrieveUser(client, username, password, callback);
          },
          function(user, callback) {
                passportSerialize(user, callback);
          }
        ], function(err, result) {
           if(err)
              console.err(err);
            else
              console.log("User authenticated, let her in");
        });
    }
    

    I hope you can see how this is much much better.

提交回复
热议问题