Source: developer.mozilla.org
new Promise((resolveOuter) => {
resolveOuter(
new Promise((resolveInner) => {
setTimeout(resolveInner, 1000);
})
);
});
This promise is already resolved at the time when it's created
(because the resolveOuter is called synchronously), but it is resolved
with another promise, and therefore won't be fulfilled until 1 second
later, when the inner promise fulfills.
My Inference: Even a pending promise counts as a resolved promise therefore the statement
this promise is already resolved at the times it's created
My Question: How does resolveOuter being called synchronously affect the resolution of a promise? Is it the mere fact that the newly created promise needs to exist at a certain state? I know I'm missing something deeper here. I'm very new to promises, can somebody please elaborate?
The outer promise calls resolveOuter() immediately (synchronously), BUT you're calling resolve() with another promise that is still pending. That means it will not yet be resolved until the child promise is also resolved.
So, the outer promise is immediately in the pending state, but it's watching the inner promise. The inner promise is also immediately in the pending state since it's been created, but resolve() has not yet been called.
Then, the setTimeout() fires and that resolves the inner promise. The outer promise is watching the inner promise (with the equivalent of .then()) and when it sees that the inner promise resolves, it can then resolve itself.
How does resolveOuter being called synchronously affect the resolution of a promise?
If you were calling resolveOuter() with a static value, then the outer promise would immediately go to the fulfilled state. But, you called resolveOuter(somePendingPromise) so that outer promise is still pending and is waiting for the inner promise to fulfill/reject.
Related
I'm getting confused with the different terminology thrown around. From my understanding, a promise can be:
fulfilled
rejected
pending
settled
resolved
defer
Does resolve mean settled? or does it mean its fulfilled? and what the heck is defer?
Terminology can be hard.
Let's take from the Promises/A+ specification and the respective ES6 section that there are 3 states:
pending - the promise does not have taken a value yet, it's future is still uncertain.
fulfilled - the promise successfully got a result value "assigned"
rejected - the promise is given a reason why no result could be acquired, typically an error.
The term settled is a hyperonym for fulfilled and rejected, meaning either - the opposite of pending.
The dynamic verbs fulfill and reject describe changing the state from pending into either the fulfilled or rejected. These transitions are called fulfillment or rejection of the promise.
Those were easy. Now, resolve is a different beast. It sometimes is used synonymous to "fulfill", but it would better be understood as settling the promise's fate to either fulfilled or rejected. The resolution (seldom: settlement) of a promise means that it leaves the pending state. But not even that is accurate - the problem is the recursive nature of the Promise Resolution Procedure:
resolving a promise with a "plain" value means fulfilling it
resolving a promise with a promise (or thenable) means adopting its state:
resolving with a fulfilled promise is a fulfillment
resolving with a rejected promise is a rejection
resolving with a pending promise means waiting for its resolution
Yes, if a promise is resolved it might not even be known whether it's going to be fulfilled or rejected. But it means the fate is no longer undetermined, as it's bound to the promise that we resolved with (notice that you can resolve a promise only once).
Ignoring this special case, a resolved promise usually means a settled promise.
Or, to cite the ECMAScript 6 Specification:
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.
and what the heck is defer?
Deferring a result means that you return an (asynchronous) promise for the result, and not the result directly (synchronously). And also return a deferred rejection instead of throwing synchronously.
Notice that "defer" is also used in some libraries (Q) as the method name to construct a Deferred object - see this answer on The differences between Deferred, Promise and Future for a good explanation.
Oh, and never trust variable names: defer might as well be an abbreviated "deferredObject".
The three promise states are listed in section 2.1 of the Promises/A+ specification.
From the specification:
So here are each of the terms you asked about:
Pending is the initial promise state. The operation represented by the promise has not yet been filfilled or rejected.
Fulfilled is another of the three promise states. It means that the promise has been resolved and now has its resolved value. The operation represented by the promise has been completed successfully.
Rejected is another of the three promise states. It means that the promise has been rejected and now has its rejected reason. The operation represented by the promise failed to obtain a value and thus has a reason for failing to do so (typically an error code or error object, but it can be anything).
Settled is a term that means the promise is either fulfilled or rejected (e.g. it's not pending any more), but it is not a separate state just a descriptive term to indicate it is no longer pending.
Resolved is a term that is often used to mean the same as fulfilled, but the two are not exactly the same. A promise can be resolved with a value which leads to fulfillment or it can be resolved with a rejected promise (which leads to rejection of this promise) or it can be resolved with a pending promise (which means it will now be waiting on the eventual state of some other promise).
It's hard to say exactly what you mean by defer. Promises are often classified as deferred objects in that they are an object that represents an action and result that is deferred to the future (it will occur in the future). In some promises implementations, there are actually two types of objects, a deferred object and a promise object. The deferred object is a superset of the promise object. Both can observe when the action is resolved or rejected with .then() handlers. But, only the deferred object can actually change the state to resolved or rejected.
In jQuery, you can create a deferred object with $.Deferred(). In other implementations such as ES6 promises, you just have promise objects with a constructor callback that has reject and resolve functions. The world is presumably moving toward what ES6 will have.
jQuery example that uses a deferred object:
function delay(t) {
var defer = $.Deferred();
setTimeout(function() {
defer.resolve();
}, t);
return defer.promise()
}
delay(200).then(function() {
// run my delayed function now
doMyThing();
});
ES6 promise example:
function delay(t) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve();
}, t);
});
}
delay(200).then(function() {
// run my delayed function now
doMyThing();
});
Domenic Denicola's "States and Fates" is a good, pithy summary.
States:
a promise is fulfilled if promise.then(f) will call f "as soon as possible"
a promise is rejected if promise.then(undefined, r) will call r "as soon as possible"
a promise is pending if it is neither fulfilled nor rejected.
Fates:
a promise is resolved if trying to resolve or reject it has no effect, i.e. the promise has been "locked in" to either follow another promise, or has been fulfilled or rejected
a promise is unresolved if it is not resolved, i.e. if trying to resolve or reject it will have an impact on the promise.
Follow the link for details 'relating states and fates'.
Can I confirm if my understanding of the code below is roughly correct?
function fetchDog(){
k = fetch("https://dog.ceo/api/breeds/image/random")
console.log(k);
};
fetchDog();
k is displayed on the console as a Promise object. Because the console is live, this promise does resolve to fulfilled.
function fetchDog(){
fetch("https://dog.ceo/api/breeds/image/random")
.then(response => console.log(response))
};
fetchDog();
The fulfilled promise resolves to a response object. It ceases being a Promise object because it's resolved to something else entirely.
No.
A promise will always be a promise. It's state may change from pending to resolved, but nothing about promises causes variables referencing them to mutate to reference their resolved value.
To get the resolved value you need to use then() or await.
First of all, a resolved promise is still a promise. The value doesn't magically get overwritten. What .then is doing is it's essentially adding a function as a listener and saying, once the promise resolves, run this function with the value that the promise is resolved with. So, inside the function, response is not the promise, but the contents of the promise. The actual promise still lives on. Consider this code:
const x = Promise.resolve("hello"); // generate a promise that immediately resolves to "hello"
x.then(v => console.log(v));
x.then(v => console.log(v));
// "hello" is logged twice
If a promise is created this way:
myPromise = new Promise(function(resolve, reject) {});
Can this promise be ever resolved by any way? Obviously, the executor is not resolving it in this case, so can the promise be ever resolved?
I think if it is jQuery, it can be resolved by deferred.resolve() so that the related promise deferred.promise() is resolved.
No, the promise can only be resolved or rejected by the resolve and reject functions, respectively.
If these functions aren't called nor exposed, the promise will remain in pending state forever.
That's also a security level, as it helps you ensure the promise you wait for will resolve to the value you expect and when you expect; and allows you to safely return an internal promise, as it is (without any hazards or leaking secrets).
To make a promise, that relies on another promise you don't have control over, but can be resolved (or rejected) manually, regardless of the original, you can use the Promise.race() function:
//The original promise that may pend forever
const original = new Promise(()=>{})
//Controller promise, whose resolver is exposed (or contains the logic needed for "manual" resolution)
let resolve
const controller = new Promise(rs=>{resolve=rs})
//The promise you wait for (and can be resolved or rejected either by `original` or `controller`)
const mixed = Promise.race([original,controller])
mixed.then(console.log)
setTimeout(()=>resolve('Resolved'), 2000)
Assign the resolve function to a variable outside the scope of the promise
Following is the native Javascript code:
var first = Promise.resolve(1);
first.then((i)=>console.log(1))
When I inspect first in the console of Chrome, it shows its status is "resolved"
> first
Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 1}
However, when I inspect first.then((i)=>console.log(1)) in the console of Chrome, it shows that its status is "pending"
> first.then((i)=>console.log(1))
1
Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
This looks confusing to me because I expected the first.then((i)=>console.log(1)) has the status of resolved as the callback within the then method has already been executed and finished.
Does anyone have ideas about this?
Promise.resolve().then(fn) returns a new promise that is not yet resolved, but will be resolved on the next tick after the current thread of execution unwinds and finishes.
Thus, if you immediately check to see if the returned promise is yet resolved, it will not be. But, if you wait until the next tick, it will then be resolved and the .then() handler function will be fired at that time.
To explain, each chained call to .then() returns a new promise that is chained to the prior one. And, per the Promise A+ specification, all .then() callback handlers are fired asynchronously after the stack has unwound (technically it says something like "when only platform code is on the stack").
So, .then() runs immediately and synchronously. It stores the callback(s) you pass it in the promise object and then those callbacks are actually called asynchronously some time in the future. If the promise is resolved quickly, then the fulfill callback will be called on the next "tick" when the current thread of execution has finished.
This stack unwinding and firing on the next tick is to make it so that .then() handlers are consistently firing asynchronously, not matter how quickly the promise is resolved. This allows the calling code to be written in one consistent manner when the promise is resolved immediately, in 1ms or in 20 minutes. They will all get resolved asynchronously some time in the future and thus the calling code can treat them all the same. The only thing that will be different is how long from now they are resolved or rejected.
For promises that confirm to Promise/A+ spec, for a then call of the form
promise.then(onFulfilled, onRejected)
there is a condition that
onFulfilled or onRejected must not be called until the execution context stack contains only platform code.
So, assuming Chrome adheres to this spec for its promises, and only sets the (internal?) Promise status to resolved once the callbacks have been called, calling
Promise.resolve(1).then(onFulfilled, onRejected);
will always show an unresolved promise since the stack has not yet cleared and the callbacks not yet called. However,
var derived = Promise.resolve(1).then(onFulfilled, onRejected);
And then later, in the inspector calling
derived;
will show a resolved promise since the stack has cleared and the callbacks called. The call to
Promise.resolve(1);
is not subject to the constraint on having to wait for the stack to clear, and so returns an immediately resolved promise.
Let's say I have a Promise like this:
var promise = new Promise(function(resolve, reject) {
// Do some async thing
});
promise.then(function(response) {
// Then do some other stuff
});
What happens if the async Promise completes before I call .then()? Normally, I'd only have long running tasks in the Promise function, but what if it completes really quickly one time?
As expected: then callback will get called immediately in this case if then was called after promise has already resolved.
It's easy to test:
var promise = new Promise(function(resolve, reject) {
resolve(123);
});
setTimeout(function() {
promise.then(function(response) {
alert(response);
});
}, 1000)
As others have already pointed out, you can add callbacks with .then before or after the promise has been resolved, and you can even add more than one callback.
These callbacks will be called in the order they were added, but always asynchronously, after the current turn of the event loop. So if the promise has already been resolved when you add a .then, your handler will be called immediately, but in the "ascynchronous sense".
The Promises/A+ spec says:
[...] onFulfilled and onRejected execute asynchronously, after the event loop turn in which then is called, and with a fresh stack.
A promise has state, which means that even after the promise gets fulfilled, you can attach callbacks using .then to it, and they will be called, with the same result as if the promise was fulfilled after they were attached.
Fulfilled is the final state of a successful promise. This means that you can attach more handlers to the fulfilled promise in the future, using the promise as a cache for the original response.
.then() on MDN
then()
Calls one of the provided functions as soon as this promise is either
fulfilled or rejected. A new promise is returned, whose state evolves
depending on this promise and the provided callback functions.
The appropriate callback is always invoked after this method returns,
even if this promise is already fulfilled or rejected. You can also
call the then method multiple times on the same promise, and the
callbacks will be invoked in the same order as they were registered.
The then callback will never get called before the promise is resolved, which is what I think you mean by complete. However, if a promise is resolved before it is returned from a function, any additional success callbacks chained after that moment will still be executed. For example,
function getMeAResolvedPromise() {
var prom = new Promise();
prom.resolve('some val');
return prom;
}
...
getMeAResolvedPromise.then(function(result) {
// this will still be executed
});