使用其他模块中的函数避免使用异步回调地狱

时间:2016-03-29 22:56:52

标签: javascript node.js asynchronous

我有一个用户模块,我在其中定义要在代码中使用的函数。当我创建密码时,我想使用这些功能:

用户模块:

//insert a local user into the database
User.prototype.insertLocalUser = function (email, password, cb) {

  var sql = "INSERT INTO VCUSER ( VCUSER_EMAIL, VCUSER_PASSWORD ) values ('" + email
    + "','" + password + "')";

  db.get().query(sql, function (err, rows) {
    if (err) return cb(err);

    return cb(err, rows);
  });
};

//generate hash function for password
User.prototype.generateHash = function (password, cb) {

  bcrypt.genSalt(10, function(err, salt) {
    if (err) return cb(err);

    bcrypt.hash(password, salt, null, function(err, hash) {
      return cb(err, hash);
    });
  });
};

Passport.js:

这是我正在这样做的地方,认为这不是太糟糕但我目前仍然试图了解如何使用异步修复一个简单的嵌套回调问题,我不想继续前进更多复杂的回调巢。

//minor callback hell
      user.findByEmail(email, function (err, rows) {
        if (err) return done(err);

        if (rows.length) { //user must already exist prompt user
          return done(null, false, req.flash('signupMessage', 'That email is already taken.'));
        } else {

          user.generateHash(password, function (err, hash) {
            if (err) return done(err);

            //insert a user with the newly hashed password into the database
            user.insertLocalUser(email, hash, function (err, rows) {
              if (err) return done(err);

              user.VCUSER_USERID = rows.insertId;

              //return the user we are done, they should be serialized and redirected
              return done(null, user);
            });
          });
        }
      });

我正在尝试做这样的事情:

//first search to see if the user already exists
  user.findByEmail(email, function (err, rows) {
    if (err) return done(err);

    if (rows.length) { //user must already exist prompt user
      return done(null, false, req.flash('signupMessage', 'That email is already taken.'));
    } else {
      async.series([
        //code avoid callback hell here
        user.generateHash... {

        }

        user.insertLocalUser() {

        }
      ]);
    }
  });

我看了很多例子,但我似乎找不到有人在异步中调用外部模块代码的东西。

1 个答案:

答案 0 :(得分:1)

感谢@ Bergi的反馈意见,我将展望未来。无论是否有人想要这样做,这是我的解决方案。我强烈建议您查看async waterfall documentation这是我发现的一些更好的材料。

async.waterfall([
    //look in database for existing users with email inputed return as results
    function findUser(cb) {
      var sql = "SELECT * FROM VCUSER WHERE VCUSER_EMAIL = '" + email + "'";

      db.get().query(sql, function (err, result) {
        if (err) { cb(err); }

        cb(null, result);
      });
    },
    //check if there were any results, if so prompt, if not continue with user creation
    function generateHash(result, cb) {
      if (result.length) { return done(null); } //TODO determine how this is handled back to UI

      bcrypt.genSalt(10, function(err, salt) {
        if (err) { cb(err); }

        bcrypt.hash(password, salt, null, function(err, hash) {
          cb(null, hash);
        });
      });
    },
    //using recently generated hash create a user
    function insertNewUser(hash, cb) {
      var sql = "INSERT INTO VCUSER ( VCUSER_FIRSTNAME, VCUSER_LASTNAME, VCUSER_EMAIL, VCUSER_PASSWORD ) " +
        "values ('" + req.body.firstName + "','" + req.body.lastName + "','" + email + "','" + hash + "')";

      db.get().query(sql, function (err, rows) {
        if (err) { cb(err); }

        cb(null, rows);
      });
    }
  ], function (err, rows) {
    if (err) { return done(err); }
    else {
      user.VCUSER_USERID = rows.insertId;
      return done(null, user)
    }
  });
})