0

First of all I'd like to ask if this is a good solution for working with promises.

app.get('/sample', function(req, res) {

var promiseFlow = {

    step1: function() {
        return modelPromise1();
    },

    step2: function(result) {
        if(result) {
            // I would like to stop the promise chain here
            res.send(result);
        } else {
            return modelPromise2();
        }
    },

    step3: function(result) {
        if(result) {
            res.send(result);
        } else {
            // This will be sent always
            res.send(false);
        }
    }

}

promiseFlow.step1()
    .then(promiseFlow.step2)
    .then(promiseFlow.step3)
    .catch(function(error) {
        console.log(error);
    });

});

User model example:

_self.get_user_info = function(_guid) {
var deferred = modules.Q.defer();

modules.system.db.connect(deferred, function(connection) {
    var query = modules.qb.select().from('users')
                    .field('_guid')
                    .field('username')
                    .where('_guid = ?', _guid);

    connection.query(query.toString(), function(error, result) {
        connection.release();
        if(error) {
            deferred.reject(error);
            return; 
        }
        if(result.length) {
            deferred.resolve(result);
        } else {
            deferred.reject(null);
        }

    });
});
return deferred.promise;

}

My main problem is with this that I don't know how to break the chain to not execute the next step. The res.send(false) will happen anyway in step3. Can this thing work or I should choose an other pattern for this.

Thanks!

Akos
  • 77
  • 7

2 Answers2

1

I think the problem is you're approaching it from the other way around. Promises should be fulfilled on success, and rejected on error.

The then method gets two parameters: the first one is to handle success, the second one is to handle rejection. On rejection, the control flow jumps to the next rejection handler - on fulfilment, it just goes to the next fulfilment handler. Usually I prefer this to catch, as it makes it more clear whose error is handled.

Looks like you're trying to handle success (when you send the response) as an error, and vice versa. You should break the chain on error, not on success.

Also, your promises should be rejected on error (e.g. throw an exception on failure, or reject the promise) instead of just not returning a result.

You would need something like this instead:

promise1()
  .then(function(result) {
    res.send(result);
  }, function(error) {
    return promise2()
      .then(function(result) {
        res.send(result);
      }, function(result) {
        res.send(false);
      });
  });
sevcsik
  • 1,210
  • 12
  • 12
  • My first approach was kinda like this but that led me to a pyramid code which I'm trying to avoid. Let me explain my code structure a bit. I have a user model which contains mysql queries returning a promise. I resolve the promise if I get the result and only reject the promise if there was an error with the connection. So if I'm right the way you've suggested I would need to wrap that model method call into another promise and handle the result to keep my models in the original matter. Or another way just got in my mind if reject the model's method promise even if it's an error ora bad result – Akos Oct 08 '15 at 11:19
  • Rejection is not just about errors - it's about not getting the data what you "promised" to return. If your model method returns a promise for a piece of data, you can either reject it if there's an error or if that piece of data is not available. In the latter case, you can return a fallback promise (promise2 in the example), and in the former case, you can just re-throw the error, to be caught in a `catch` which handles every error. You're right that this has to be implemented in your model, but you don't have to create a wrapper for it, you can just chain a `then` after it which handles it – sevcsik Oct 08 '15 at 11:29
  • Looking at your updated question, seems like you already reject the promise when there are no results, so that model would work fine with the solution in my answer. – sevcsik Oct 08 '15 at 12:14
0

That literally makes no different but complicates the code.

Try this:

modelPromise1()
  .then(function(result) {
    if (!result) return modelPromise2();
  }).then(function(result) {
    if (!result) res.send(false);
    else res.send(result);
  }).catch(/*...*/);
Louay Alakkad
  • 7,132
  • 2
  • 22
  • 45