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:
await
construct?Regarding your first question (in its original and updated versions):
What gets passed to the Promise as the
resolve
/reject
functions?Who passes the parameters to the Promises' anonymous function? It is the
await
construct?What exactly gets passed?
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:
- Let resolve be CreateBuiltinFunction(stepsResolve, lengthResolve, "", « [[Promise]], [[AlreadyResolved]] »).
[...]
- Let reject be CreateBuiltinFunction(stepsReject, lengthReject, "", « [[Promise]], [[AlreadyResolved]] »).
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, the new Promise()
expression has fully evaluated, and the return
statement can execute. Only then the await
operator will execute.
Then the second question in the original post:
Are they being passed implicitly by the
await
clause?
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 the resolve
or reject
functions that you received in the promise constructor callback. The await
operator merely attaches then
callbacks to the promise: one for when it fulfills, another for when it rejects. These handlers are not resolve
and reject
. While the resolve
and reject
functions set the state of a promise, the handlers (that await
registers) merely react to a state change, just like you expect from any then
/catch
callback.