Await equivalent of ‘Promise.resolve().then()’?
I’m familiar with Promises, but have inherited some rather unusual code that, rather than making a new Promise()
, uses the following:
Promise.resolve().then(
function() {
// Do useful things
}
)
From my research, this is a weird version of setImmediate – ie, run the following function on the next tick.
What would be the await
version of this?
There may be two different reasons for the Promise.resolve()
. You touched on one of them:
Defer until the end of the current run of the JS event loop
Here the obvious answer is await Promise.resolve();
.
await undefined
does the same thing implicitly, but why not be explicit?
Singular error handling
Promise.resolve()
is also often seen at the head of a promise chain for singular error handling:
const doSomething = x => new Promise(r => setTimeout(() => r(x), 1000));
Promise.resolve()
.then(() => doSomething(""())) // bug!
.then(() => doSomething("else"))
.catch(e => console.log("Got " + e)); // Got TypeError: "" is not a function
Without it, the first step may throw an exception instead, which may be unexpected!
const doSomething = x => new Promise(r => setTimeout(() => r(x), 1000));
doSomething(""()) // bug!
.then(() => doSomething("else"))
.catch(e => console.log("Got " + e)); // uncaught!
Here the answer is: you no longer need the Promise.resolve()
prologue with async/await.
async
functions implicitly catch synchronous exceptions and return a rejected promise instead, guaranteeing singular error handling and a promise return value:
const doSomething = x => new Promise(r => setTimeout(() => r(x), 1000));
(async () => {
await doSomething(""()); // bug!
await doSomething("else");
})().catch(e => console.log("Got " + e)); // Got TypeError: "" is not a function
Not only is this a nice invariant and less to type, unlike the Promise.resolve()
kludge, it actually still calls doSomething
synchronously:
function doSomething() {
console.log("doSomething() called");
""() // bug!
return new Promise(r => setTimeout(() => r(x), 1000));
}
(async () => {
await doSomething();
await doSomething("else");
})().catch(e => console.log("Got " + e)); // Got TypeError: "" is not a function
console.log("here");
This would be pretty hard to pull off any other way. Another reason async/await is great!
Just await
something.
If you give await
an expression which is not a promise, it will behave like
await Promise.resolve(<nonPromiseExpression>)
So await undefined
will cause the rest of the async function to be executed asynchronously. Take these two implementations of setImmediate
as an example:
var setImmediate = function (fn) {
Promise.resolve().then(fn);
};
console.log('A');
setImmediate(function () {
console.log('E');
});
console.log('B');
setImmediate = async function (fn) {
await undefined;
fn();
};
console.log('C');
setImmediate(function () {
console.log('F');
});
console.log('D');
I have inherited some rather unusual code that, rather than making a
new Promise()
uses aPromise.resolve().then(…)
. From my research, this is a weird version of setImmediate – ie, run the following function on the next tick.
That’s a side-effect, but probably not the intended purpose of this construct. The main point is that the “useful code” in the then
callback is throw
-safe and can easily return
plain values and promises alike, starting a usual promise chain. It could have been written with new Promise
as well, but that would have required to use a resolve
call instead of the usual return
.
What would be the
await
version of this?
Literally, await Promise.resolve();
(which could be shortened to the equivalent await undefined;
statement). However, if it was done for the purposes of error handling alone (which is likely), just omit it. async function
s will transform exceptions into rejections by default.