Question

I've got a single page which is an account settings page. In it, I allow my users to update their avatar (if they've attached an image), change their email (if it has been changed from the original), and change their name and password.

Right now, I'm using async's waterfall method, but am swapping out async for Q since I prefer the syntax (and api). I'm wondering if this is the way that I should be using Q in replacement of async's waterfall.

I'm doing something like this:

exports.settingsAccountPOST = function(req, res) {
  var doesEmailExist = function() {
    var deferred = Q.defer();

    User.findByEmail({
      email: req.body.email
    }, function(err, user) {
      if (err) {
        deferred.reject(err);
      } else {
        deferred.resolve(user);
      }
    });
    return deferred.promise;
  };

  var updateEmail = function(email) {
    var deferred = Q.defer();

    User.updateEmail({
      userId : req.session.user.id,
      email : req.body.email
    }, function(err, updated) {
      if (err) {
        deferred.reject(err);
      } else {
        deferred.resolve(updated);
      }
    });
    return deferred.promise;
  };

  var updateName = function() {
    var deferred = Q.defer();

    if (req.body.name) {
      User.updateName({
        userId: req.session.user.id,
        name: req.body.name
      }, function(err, updated) {
        if (err) {
          deferred.reject(err);
        } else {
          deferred.resolve(updated);
        }
      });
      return deferred.promise;
    }
  };

  doesEmailExist().then(function(email) {
    if (!email) {
      return(updateEmail(email));
    }
  }).then(function() {
    return(updateName())
  }).then(function() {
    res.redirect('/account')
  });
};

Say that there is an error with the email address being used. Is there a way to "pass" it to the final call? Use case: Updated password properly, but email update didn't work, so I want to show a session flash to the user telling them they updated their password properly, but there was an issue with updating their email.

I was looking in the docs and it seems I may need to use:

.fin(function () {
});

Is this correct? If so, what should I be passing into that? Just push to an object the error that occurred within the chain and then loop through all errors and display them to the user? Or just return immediately and display the error?

Was it helpful?

Solution

If you are using Q.defer you are generally doing something wrong.

var findByEmail = Q.nbind(User.findByEmail, User);
var updateEmail = Q.nbind(User.updateEmail, User);
var updateName = Q.nbind(User.updateName, User);

//later on...

exports.settingsAccountPOST = function (req, res) {
    findByEmail({
        email: req.body.email
    })
    .then(function (user) {
        if (!user) {
            return updateEmail({
                userId: req.session.user.id,
                email: req.body.email
            });
        }
    })
    .then(function () {
        return updateName({
            userId: req.session.user.id,
            name: req.body.name
        })
    })
    .then(function () {
        res.redirect("/account");
    })
    .catch(function(e){
        //Handle any error
    });
};
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top