5

The following code returns:

output.isPending?: true
output.isRejected?: false
output.isFulfilled?: false 

Why? I was expecting output.isRejected to be true.

<html>

<head>
    <script src="http://cdnjs.cloudflare.com/ajax/libs/q.js/0.9.7/q.js"></script>
    <script src="http://jasmine.github.io/2.3/lib/jasmine.js"></script>
</head>

<body>
</body>
<script>
var output, bar;

bar = {
    doSomethingAsync: function() {
        var d = Q.defer();
        d.resolve('result');
        return d.promise;
    }
};

function Foo(bar) {
    this._bar = bar;

    this.go = function() {
        var deferred = Q.defer();
        this._bar.doSomethingAsync()
            .then(onSuccess.bind(this, deferred));

        return deferred.promise;
    }
};

function onSuccess(deferred, result) {
    deferred.reject();
}

output = new Foo(bar).go()
    .finally(function() {
        console.log('output.isPending?:', output.isPending());
        console.log('output.isRejected?:', output.isRejected());
        console.log('output.isFulfilled?:', output.isFulfilled());
    });
</script>

</html>
Ben Aston
  • 53,718
  • 65
  • 205
  • 331

2 Answers2

5

Because output is not new Foo(bar).go(). It is assigned the result of the .finally() call, and will not be resolved untill the finally callback is done.

This will work as expected:

var output = new Foo(bar).go();
output.finally(function() {
    console.log('output.isPending?:', output.isPending());
    console.log('output.isRejected?:', output.isRejected());
    console.log('output.isFulfilled?:', output.isFulfilled());
});
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
0

I stand corrected a trivial delay function is unnecessary even for API's that are oblivious to promises. I can make sure the resolve or reject is always called, but after the promise itself is returned without delay. Here is an example:

var somePromise = function(path) {
    var deferred = q.defer();

    asyncFunction.request(path, function(result) {
        if (result.error === 0 && result.json !== null) {
            deferred.resolve(result);
        } else {
            deferred.reject(result || {error: -1, message: "bad things happened"});
        }
    });

    return deferred.promise;
};

exports.someCall = function(req,res) {
    somePromise('path')
        .then(function (result) {
            ... do action ...
        }).catch(function (error) {
            ... handle error ...
        }); 
};
Michael Shopsin
  • 2,055
  • 2
  • 24
  • 43
  • 1
    There's no need to `resolve` or `reject` only after returning a promise. All callbacks are called asynchronously anyway, regardless when/how you resolve your promise. Using deferreds like this even looks a bit like the [common antipattern](http://stackoverflow.com/q/23803743/1048572). – Bergi May 19 '15 at 23:00
  • This code still allows promises to be chained, eg: `exports.someCall = function(req,res) { somePromise('path') .then(function (result) { return somePromise('new path'); }).then(function (result) { ... do something else ...` – Michael Shopsin May 20 '15 at 15:52
  • Yes it does, but the `q.delay(1)` is still unnecessary? – Bergi May 20 '15 at 16:01
  • As mentioned about [converting an API to promises](http://stackoverflow.com/q/22519784/369446) I need to call some very slow HTTP calls which do not have their own wrapper for promises. The delay allows me to build a list of expensive HTTP calls and then use `q.allSettled` to wait for the results to come in. – Michael Shopsin May 20 '15 at 18:54
  • An HTTP call might be slow, but it is not expensive. Just start all of them right now, and build a promise for each, without a delay, so that you can start waiting (`allSettled`) for them immediately. That delay does not do you any good except slowing you down 1 ms (or probably more) and increasing your memory usage. – Bergi May 20 '15 at 18:58
  • 1
    I stand corrected, removing the `q.delay(1)` doesn't cause any problems. I have some bad habits left from the old C TCP API's. – Michael Shopsin May 20 '15 at 19:09