In nearly all the documentation I read, promises are constructed with an executor function whose first argument is a function named "resolve":
var promise1 = new Promise(function(resolve, reject) {
setTimeout(resolve, 100, 'foo');
});
But to me this is extremely confusing, because promise terminology differentiates "resolved" from "fulfilled," and this distinction is not consistently observed in the executor function naming.
According to https://github.com/domenic/promises-unwrapping/blob/master/docs/states-and-fates.md and https://promisesaplus.com/, "resolved" means that the promise has entered into some final state (fulfilled, rejected, or resolved to another promise), and "fulfilled" means the promise has been resolved successfully.
However, the executor's resolve() function is used to force the promise into a "fulfilled" state.
So my question is: why isn't the executor's resolve() function named fulfill()? Am I misunderstanding something?
Here's one possible explanation.
A promise ultimately ends up fulfilled or rejected and it can be send directly to one of those states by fulfilling with a value or rejecting with a reason.
But, a promise can also be tied to another thenable and it will then track that thenable. If that thenable ends up fulfilled, this promise will be fulfilled. If that other thenable ends up rejected, this promise will be rejected.
So, with the executor, you can actually do three things:
Fulfill to a value (that is not a thenable).
Reject to a reason
Resolve to a thenable which will be tracked and whose ultimate disposition will be inherited by this promise.
Ahhh, but you don't need three functions to implement all this. You can do it with just two. #1 and #3 can use the same function and just vary what they pass to it (either a thenable or a non-thenable value). So, you need a verb that captures both #1 and #3. Folks have generally picked resolve as that verb. It is resolved to either a value or thenable.
So, you get new Promise(function(resolve, reject) {...});. You have to pick some word for the first function. Most people writing documentation picked resolve(). If you resolve to a non-thenable value, you get a fulfilled promise. If you resolve to a thenable, this promise will track that thenable and take on it's eventual state.
Related
I'm new to TypeScript and I have an async function like the one below. Can someone explain what it does and where resolve comes from? I hope I'm providing enough information for this.
async function SendMessage<T extends WorkerResponse>(msg: { id: number }): Promise<T>
{
const response = await new Promise<WorkerResponse>(resolve =>
{
waitingMessages.set(msg.id, resolve);
worker.postMessage(msg);
});
return response as T;
}
When I hover the mouse over the variables I get these:
(parameter) resolve: (value: WorkerResponse | PromiseLike<WorkerResponse>) => void
const waitingMessages: Map<number, (response: WorkerResponse) => void>
resolve comes from the Promise constructor. The Promise constructor calls the function you give it (the executor function) with two arguments. When defining an executor function, we idiomatically name the parameters to receive those arguments resolve and reject:
resolve - Resolves the promise (which may or may not fulfill it — here's my blog post on Promise terminology)
reject - Rejects the promise
The purpose of the code in the executor function is to start whatever asynchronous process the promise will report on, and then (when that process concludes), either: 1) use resolve to fulfill the promise, 2) use resolve to resolve the promise to another promise, or 3) use reject to reject the promise.
The async function you've shown does this:
Calls new Promise.
The Promise constructor calls the executor function passed to it synchronously, giving it access to resolve and reject functions. The one you've shown optimistically (and probably incorrectly) only uses a resolve parameter.
The executor code calls waitingMessages.set(msg.id, resolve);, which presumably sets up an eevn handler passing resolve as the handler implementation, and then worker.postMessage(msg); to send the message.
The code awaits the promise. (Which makes SendMessage return the promise it implicitly creates; it'll settle the promise it returns later.)
At some point, presumably the event gets fired and waitingMessages calls resolve, which probably fulfills the promise with some value (a fulfillment value).
Because the promise is fulfilled, the await is satisfied, and response gets assigned the fulfillment value of the promise that was awaited.
SendMessage's code returns that value, which fulfills the promise SendMessage implicitly returned, using the response value as the fulfillment value of that promise.
I've avoided going into too much detail above, but that's the gist.
None of this is specifically related to TypeScript, it's just how JavaScript promises work.
I suggest reading through Using Promises on MDN or any good Promise introductory tutorial or book.
As you can see he is building a new Promise object , which takes as parameter resolve and reject .
In this case as you can see it's returning the resolve function this is as saying Promise.resolve() with some values inside of it . But you are resolving and it's returning this object
{
waitingMessages.set(msg.id, resolve);
worker.`enter code here`postMessage(msg);
});
question is not really related to typescript but to javascript promise concept and async await .
What it does is that it creates a Promise, which provides you with a resolve function that you can run to mark the promise as fulfilled. If you await the SendMessage function, the code execution will stop until the resolve function is run.
It seems to add a message ID to some form of messages queue, and then send the message via a web worker. You can read more about web workers here
const result = await SendMessage(yourMessage);
console.log('These console.logs will not be run until something in your code..');
console.log('..executes the resolve function that was being stored via waitingMessages.set');
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'.
for the following promise chain
new Promise(r=>r('b').then(()=>Promise.reject('x'))).catch(err=>console.log({error}))
the inner promise is returned, so it should bubble up and catched by the outer catch block and logs the error to the console.
but instead, it got resolved.
Promise {<fulfilled>: 'b'}
how to catch the inner promise by an outer catch block?
r (more typically called resolve) does not return a promise, so calling .then on it is an error. Normally, if an error is thrown in a promise executor function (the function you pass new Promise), the promise being created is rejected with that error. But since you've already called resolve, you've fulfilled the promise with "b", and once fulfilled it cannot be changed to being rejected, so the error occurring during the executor is just suppressed. (This is a specific case of the more general rule that once a promise is resolved [tied to an outcome] it can't be resolved differently. A promise can be resolved without [yet] being fulfilled, but fulfilling it is one way of resolving it. If you're not 100% on this promise terminology, check out my blog post here explaining it.)
If you want to resolve the promise you're creating to another promise, you pass it into the resolve function:
new Promise(resolve => {
resolve(Promise.reject(new Error("x")));
})
.then(value => console.log("value", value))
.catch(error => console.error("error", error.message));
That specific example would be an example of the Explicit promise construction antipattern (we should just use the promise from Promise.reject directly), but if you had branching logic in the promise executor and some of the branches didn't involve promises, you might do something similar to this (though stylistically it would make more sense to me to throw an error or call the reject function passed to the executor).
I know that Promises in JS are Immutable.
According to: What does it mean for promises to be immutable and their guaranteed value?
A promise is a one-way latch. Once it is resolved with a value or
rejected with a reason, its state and value/reason can never change.
So, no matter how many times you do .then() on the same promise, you
will always get the same result.
So I am confused about this image from: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
It looks like after the Promise is either fulfilled or rejected (resolved) it returns a Promise that is (pending). Why is that?
Every call to .then() or .catch() returns a new promise. That promise will be resolved or rejected depending upon what happens in the .then() or .catch() handler that it derives from when that handler is called. The promise at the start of the chain is indeed immutable, but once someone else calls .then() or .catch() on it, they get a new promise back from each of those calls whose state is determined by what happens inside the code that runs in the .then() or .catch() handler.
When you get that new promise from .then() or .catch() it will always be in the pending state because the code inside the .then() or .catch() has not yet been called (the original promise has not yet called them). Those statements just register handlers on the original promise.
When those handlers are called, they will determine the state of the new promise. If they return a plain value, that new promise will be resolved with that value. If they throw, that new promise will be rejected. If they return a promise, then that new promise will follow the eventual state of that new promise that was returned form the .then() or .catch() handler and it will resolve or reject as that returned promise does.
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'.