Consider the following code, which awaits a Promise:
async function handleSubmit() {
try {
await submitForm(answer);
} catch (err) {
console.log('Error')
}
}
function submitForm(answer) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (answer !== 'OK') {
reject(new Error('Rejected'));
} else {
resolve();
}
}, 1500);
});
}
Note that I never explicitly passed resolve
/reject
to the Promise, yet they are being passed (breakpoint in any JS console to see for yourselves). So my questions are:
- Who passes the parameters to the Promises’ anonymous function? It is the
await
construct? - What exactly gets passed?
4
Answers
When you create a new Promise, the Promise constructor automatically provides the resolve and reject functions to the executor function. These functions are used to settle the promise
Basically
resolve will mark the promise as fulfilled and provide the value whereas reject will mark the promise as rejected and provides a reason (typically an error)
The function you pass to the
Promise
constructor is executed synchronously, not when youawait
the promise or call one of its methods e.g..then()
.resolve
andreject
are passed by the constructor.Regarding your first question (in its original and updated versions):
These functions are created by the JS engine. The specifications can be found in section 27.2.1.3 CreateResolvingFunctions(promise) of the ECMA Script specification. Namely in step 4 and step 9 of that procedure they are created:
The above procedure is executed when constructing a promise, for which the procedure is defined in 27.2.3 The Promise Constructor.
Note that at this point the
await
operator is not yet relevant. This constructor callback executes synchronously as the promise is created. Only after the promise callback has executed, thenew Promise()
expression has fully evaluated, and thereturn
statement can execute. Only then theawait
operator will execute.Then the second question in the original post:
The procedure for the
await
operator can be found at 27.7.5.3 Await (value) in the same specification.It gets the promise that its operand evaluates to. NB: if it was not a promise, a new promise is created for it. But this is not your case.
Then it creates(!) both the onFulfilled and onRejected handlers (functions), which are passed as callbacks to the promise’s
then
method. Among other things, these handlers take care of resuming a suspended function.Finally, the
await
makes the function return, and it returns a pending promise (a different one from the one you created).The
await
operator does not call theresolve
orreject
functions that you received in the promise constructor callback. Theawait
operator merely attachesthen
callbacks to the promise: one for when it fulfills, another for when it rejects. These handlers are notresolve
andreject
. While theresolve
andreject
functions set the state of a promise, the handlers (thatawait
registers) merely react to a state change, just like you expect from anythen
/catch
callback.If I understand your question correctly, you are asking where
resolve
andreject
comes from?The answer is the person who wrote the code for the
Promise
object. That’s how promises are designed to work. It has nothing to do withawait
. It has nothing to do with javascript itself (except for the fact that the ECMAScript standard specifies how Promises are supposed to work).Let me give you an example.
I, slebetman, give you a library that returns some number;
The API for that library is:
Where does the
getter
function come form? It comes form me, slebetman, because I wrote the function like this:In the Promise object there is a similar construct (but probably written in C++ instead of plain JS).
A simple poor-man’s Promise constructor (that doesn’t comply with the specification) can be written like this:
Now you can use it like:
Technically even this should work;
That’s because
await
works with any function that returns an object that has a.then()
function.