RSVP Promises: Why does parent promise wait on non-chained inner promise?

88 Views Asked by At

We're using an older version of RSVP.js in several apps we built.

I expected this promise to resolve immediately while outputting "1", "2", and after 5 seconds "3". I thought the inner promise would be treated like a value.

    new RSVP.Promise(function (resolve) {
        console.log('1');

        var p = new RSVP.Promise(function (innerResolve) {
           setTimeout(function () {
               console.log('3');
               innerResolve();
           }, 5000);
        });
       resolve(p);
    }).then(function () {
        console.log('2');
    });

Instead, the inner promise appears to be treated as a chained promise.

So the actual output above is: "1", 5 second delay, "3", "2".

It was always my understanding from the RSVP documentation (https://github.com/tildeio/rsvp.js/#chaining) that chained promises have to follow a certain format. For example, if I actually wanted the latter behavior (1, 5sec delay, 3, 2), I would have written the code this way:

    new RSVP.Promise(function (resolve) {
        console.log('1. Simply resolve a value which happens to be a promise');
        resolve();
    }).then(function () {

        var p = new RSVP.Promise(function (innerResolve) {
            setTimeout(function () {
                console.log('3. This took a long time!');
                innerResolve();
            }, 5000);
        });

        // Return a promise in a then() to chain it!
        return p;
    }).then(function () {
        console.log('2. You should see this immediately!');
    });

The reason why I'm asking is because the parent promise is outside of my control (it's part of some internal framework plumbing code). My function just gets passed the parent promise's resolve and reject functions.

function myFunction(parentResolve, parentReject) {
   // my code here..
   parentResolve(new RSVP.Promise(...)); // want to resolve promise as value
}

My workaround is to wrap the promise in an object, but it's not ideal.

    new RSVP.Promise(function (parentResolve) { // no control over this
        console.log('1');

        // my code here..
        var p = new RSVP.Promise(function (innerResolve) {
           setTimeout(function () {
               console.log('3');
               innerResolve();
           }, 5000);
        });

        // Wrap it in an object
       parentResolve({result: p});
    }).then(function () {
        console.log('2');
    });

Is RSVP's chaining behavior correct? Is there a better solution than wrapping my promise in an object? I may try upgrading to the latest version of RSVP to see if it's simply due to my outdated version.

1

There are 1 best solutions below

1
On BEST ANSWER

I thought the inner promise would be treated like a value.

No, unfortunately resolve never does that. It always resolves thenables, there is no way to fulfill with a promise.

Is RSVP's chaining behaviour correct?

Yes.

Is there a better solution than wrapping my promise in an object?

Not really. But I wouldn't consider that a workaround. Either you want to transport some data that should be available immediately, before the inner promise resolves - then that data should go on the wrapper object. Or you don't need anything before the inner promise resolves and you want to await it anyway - then the default behaviour of resolving a promise with a promise is just the right thing for you. See also this answer.