2

Orchestrate has a client for NodeJS. It is based on promises so I should define a function then and a function fail. The first should be triggered when the request is successful and the second one when it fails. But sometimes it triggers both and I don't understand why.

Here is an example of a function that calls both then and fail:

user.checkToken = function (token, db, callback) {
    if (token) {
        db.get('acces_tokens', token).then(function (res) {
            if (new Date(res.body.expire) > new Date()) {
                //Token is valid
                callback(res.body.user, res.body.expire);
            } else {
                //Token has expired
                callback(false, "Token has expired");
            }
        }).fail(function (err) {
            callback(false, "ERROR");
        });
    } else {
        callback(false, "A token is needed");
    }
};

I do not understand it :(

EDIT: It turn out it only does this when I call it from certain functions. This is even weirder.

EDIT 2: I've been doing some debuging. I console.logged the entire promise like this:

console.log(
    db.get('acces_tokens', token)
        .then(function (res) {
            if (new Date(res.body.expire) > new Date()) {
                //Token in valid
                callback(res.body.user, res.body.expire);
            } else {
                //Token has expired
                callback(false, "Token has expired");
            }
        }).fail(function (err) {
        callback(false, "ERROR");
        })
)

And I got this:

{ promise: [Circular],
  _isPromise: true,
  _successFn: null,
  _failFn: [Function],
  _scope: [Circular],
  _boundArgs: null,
  _hasContext: false,
  _nextContext: undefined,
  _currentContext: undefined }

As you can see _successFn is null. I guess this is the problem but I do not understand why it is null :(

Pep Rodeja
  • 47
  • 7
  • Its just plain weird - in many implementations of Promises `.then` is called both for success and failure (jQuery for example) - but your use is inline with the docs. – max May 16 '15 at 08:46
  • Yes that was my first thought! I looked the documentation carefully and I think this is correct. I even tried to swap .then for .success but it didn’t do the trick :( – Pep Rodeja May 16 '15 at 08:51
  • Could be related to https://github.com/orchestrate-io/orchestrate.js/issues/52 – max May 16 '15 at 08:53
  • 1
    It turns out I had an error with a subsequent promise. Once fixed this started working. Thought the problem now is solved, I do not understand why promises can affect each other. – Pep Rodeja May 16 '15 at 09:14
  • Basically, putting `.fail` (which should be equivalent to `.then(null, function () { ... })`) means to handle any errors from all previous promise functions if they haven't been handled yet. jQuery doesn't really have "proper" promises, so to speak. – Qantas 94 Heavy May 16 '15 at 13:12
  • With the expression `myPromise.then(successHandler).fail(errorHandler)`; (1) that `successHandler` and `errorHandler` should both fire is entirely reasonable, given that `.then()` returns a new promise and its `successHandler` might itself return a rejected promise; (2) the expression is not an "entire promise" as such - it's a *promise chain*, with a starter promise (`myPromise`) and a second promise returned by `.then()`, which the chain ultimately returns. – Roamer-1888 May 16 '15 at 17:42
  • This comment is totally _Irelevent_: [Promises/A+ Performance Hits You Should Be Aware Of](http://thanpol.as/javascript/promises-a-performance-hits-you-should-be-aware-of/) – xiaoyi May 17 '15 at 09:55

1 Answers1

0

But sometimes it triggers both and I don't understand why.

Because in the pattern you used - shortened to promise.then(callback).fail(callback) - callback might be called twice. If promise succeeds, your first callback is called, but when that callback throws an exception then the promise returned by promise.then(callback) is rejected and will call the fail callback you attached to it.

You'll need to use something along the lines of promise.then(callback, callback) to prevent this from happening. See When is .then(success, fail) considered an antipattern for promises? for more explanations.

Of course, it would be better if you'd screw callbacks alltogether and just return a promise from your checkToken function :-)

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Thank you! I didn't completely understand how promises work. I'll use your recommendation and return a promise :) – Pep Rodeja May 17 '15 at 19:28