Fulfill (Don't Resolve) Promise with Another Promise

Fulfill (don't resolve) promise with another promise

There doesn't seem to be a solution apart from the workaround I already described in the question. For future reference, if you want to fulfill (rather than resolve) a promise p with a value val, where val is another promise, then just calling the promise resolution function for p with argument val won't work as expected. It would cause p to be "locked in" on the state of val, such that p will be fulfilled with val's resolution value once val is fulfilled (see spec).

Instead, wrap val in another object and resolve p with that object:

var resolveP;  // Promise resolution function for p

var p = new Promise(
function(resolve, reject) {
resolveP = resolve;
}
);

function fulfillPwithPromise(val) { // Fulfills p with a promise val
resolveP({promise: val});
}

p.then(function(res) {
// Do something as soon as p is fulfilled...

return res.promise;
}).then(function(res) {
// Do something as soon as the second promise is fulfilled...
});

This solution works if you already know that val is a promise. If you cannot make any assumptions about val's type, then you seem to be out of luck. Either you have to always wrap promise resolution values in another object, or you can try to detect whether val has a field then of type "function" and wrap it conditionally.

That said, in some cases the default behavior of promise resolution may actually have the desired effect. So only use the workaround described above if you are sure that you want to fulfill instead of resolve the first promise with the second one.

Passing another promise to a promise handler

Resolving a promise to another promise will automatically make it wait for the other promise's result.

This is what makes promises chainable (returning further promises in then() callbacks).

JS Promises: Fulfill vs Resolve

Indeed, the resolve callback does not imply that the promise will be fulfilled.

The terms fulfilled, rejected, pending, settled, resolved and locked-in are defined in
the EcmaScript2015 specs, 25.4 Promise Objects:

Any Promise object is in one of three mutually exclusive states: fulfilled, rejected, and pending:

  • A promise p is fulfilled if p.then(f, r) will immediately enqueue a Job to call the function f.

  • A promise p is rejected if p.then(f, r) will immediately enqueue a Job to call the function r.

  • A promise is pending if it is neither fulfilled nor rejected.

A promise is said to be settled if it is not pending, i.e. if it is either fulfilled or rejected.

A promise is resolved if it is settled or if it has been “locked in” to match the state of another promise.
Attempting to resolve or reject a resolved promise has no effect. A promise is unresolved if it is not resolved.
An unresolved promise is always in the pending state. A resolved promise may be pending, fulfilled or rejected.

A short overview, where I will use the term "autonomous" as the opposite of "locked in". They are the two possible values for a promise's dependency situation:










































actiondependencystateresolved?settled?
new Promise((resolve, reject) => ...)autonomouspendingnono
...resolve(thenable)locked-inpending*yesno
...resolve(other)autonomousfulfilledyesyes
...reject(any)autonomousrejectedyesyes

Is it possible for an 'await' to resolve to a Promise?

No, it's impossible for an await expression to result in a promise.

Just like you cannot fulfill a promise with another promise, and like then() never calling the fulfillment handler with a promise.

What happens if you don't resolve or reject a promise?

A promise is just an object with properties in Javascript. There's no magic to it. So failing to resolve or reject a promise just fails to ever change the state from "pending" to anything else. This doesn't cause any fundamental problem in Javascript because a promise is just a regular Javascript object. The promise will still get garbage collected (even if still pending) if no code keeps a reference to the promise.

The real consequence here is what does that mean to the consumer of the promise if its state is never changed? Any .then() or .catch() listeners for resolve or reject transitions will never get called. Most code that uses promises expects them to resolve or reject at some point in the future (that's why promises are used in the first place). If they don't, then that code generally never gets to finish its work.

It's possible that you could have some other code that finishes the work for that task and the promise is just abandoned without ever doing its thing. There's no internal problem in Javascript if you do it that way, but it is not how promises were designed to work and is generally not how the consumer of promises expect them to work.

As you can see if the status is 401, I am redirecting to login page.
Promise is neither resolved nor rejected.

Is this code OK? Or is there any better way to accomplish this.

In this particular case, it's all OK and a redirect is a somewhat special and unique case. A redirect to a new browser page will completely clear the current page state (including all Javascript state) so it's perfectly fine to take a shortcut with the redirect and just leave other things unresolved. The system will completely reinitialize your Javascript state when the new page starts to load so any promises that were still pending will get cleaned up.

Resolving a Promise within a Promise

new Promise((res, rej) => res(promiseA)) is known as promise construction antipattern and there is never a good reason to do that.

This code

let promiseB = new Promise((res, rej) => res(promiseA))

is equivalent to

let promiseB = promiseA;

I expect resolvedVal to be promiseA, and not the resolved value of promiseA. Why is this not the case?

This is how promises work and a reason why this pattern is useful to avoid callback hell. A promise of a value becomes a value when a promise is chained with then.

As Promise/A+ specification states:

The promise resolution procedure is an abstract operation taking as input a promise and a value, which we denote as [[Resolve]](promise, x). If x is a thenable, it attempts to make promise adopt the state of x, under the assumption that x behaves at least somewhat like a promise. Otherwise, it fulfills promise with the value x.

ES6 Promises/calling a function after multiple promises are fulfilled (can't use Promises.all)

To do it strictly using ES6 promises, you will need to wrap each promise in another wrapper promise, which gets resolved when the wrapped promise is fulfilled or rejected.

You can do that like this:

Promise.all( 
promises.map( promise => Promise.resolve( promise ).catch( _=>_ ) )
).then ( function ( ) {
// All promises finished
} );

This assumes that promises is an array of promises and/or values.

What should happen if you resolve a promise with another promise?

What does the ECMAScript 6.0 specification say about a Promise resolving another Promise?

You can read it yourself here: http://www.ecma-international.org/ecma-262/6.0/#sec-promise-resolve-functions

When the argument is a thenable, a PromiseResolveThenableJob will be queued.

Should it adopt the state of the other Promise by attaching a then to that Promise which would resolve this one?

Yes. The .then() method will be called with a resolver and rejecter function.

I tried this snippet in Chrome and here is what I get and it seems to just resolve the Promise1 with Promise2 is that fine?

Yes. It's only resolved for now.


I do have to admit, my current Chrome Version (48.0.2564.82, V8 4.8.271.17) doesn't exactly comply to this algorithm (which might not be a bad thing per se, and avoids memory problems, but can be unexpected).

It is lazy, and only schedules the job once an actual callback is interested in the result. And it doesn't pass a resolver to the then method, but the actual callback that wants to know the result.

> var resolve1, resolve2;
> var promise1 = new Promise(function(r){ resolve1 = r; });
> var promise2 = new Promise(function(r){ resolve2 = r; });
> promise2.then = function(...args) { console.log(...args);
> return Promise.prototype.then.call(this, ...args); };
> resolve1(promise2);
undefined
// you'd expected a call to the then method here
> promise1
Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: Promise}
> promise2
Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
> resolve2(42)
undefined
// or at least here
> promise1
Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: Promise}
> promise2
Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 42}
> promise1.then(x => console.log(x))
x => console.log(x), PromiseIdRejectHandler() { [native code] }
// but it only is here
42
Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
> promise2.then(x => console.log(x))
x => console.log(x)
42
Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
> promise1.then(x => console.log(x))
x => console.log(x), PromiseIdRejectHandler() { [native code] }
// hell they're even calling it multiple times!
42
Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}

> var resolve1, resolve2;
> var promise1 = new Promise(function(r){ resolve1 = r; });
> var thenable = {then:function(r) { console.log(...arguments); resolve2 = r; }};
> resolve1(thenable);
undefined
// you'd expected a call to the then method here
> promise1
Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: Object}
> thenable
Object {}
> resolve2(42)
Uncaught TypeError: resolve2 is not a function(…)
// uh. yeah.
> promise1.then(x => console.log(x))
() { [native code] }, () { [native code] }
// ah there was the call, even with a resolver
Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
> resolve2(42)
42
undefined
> promise1.then(x => console.log(x))
() { [native code] }, () { [native code] }
// but now they fucked up.
// Instead of another call on the thenable, you'd expected the result to be logged
Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
> resolve2(42)
42
// OMG.
undefined

Resolve Javascript Promise outside the Promise constructor scope

simple:

var promiseResolve, promiseReject;

var promise = new Promise(function(resolve, reject){
promiseResolve = resolve;
promiseReject = reject;
});

promiseResolve();


Related Topics



Leave a reply



Submit