Skip to content

Instantly share code, notes, and snippets.

@joeytwiddle
Last active August 8, 2023 09:21
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joeytwiddle/ff0a9cf92be0366b274e4283a8b5a935 to your computer and use it in GitHub Desktop.
Save joeytwiddle/ff0a9cf92be0366b274e4283a8b5a935 to your computer and use it in GitHub Desktop.
async function getFoo (bar) {
const baz = 2 * bar;
const root = await asyncSqrt(baz);
return 2 * root;
}
// Is the same as
function getFoo (bar) {
return Promise.resolve().then(() => {
const baz = 2 * bar;
return asyncSqrt(baz).then(root => {
return 2 * root;
});
});
}
// (Aside) It is not quite the same as
function getFoo (bar) {
const baz = 2 * bar;
return asyncSqrt(baz).then(root => {
return 2 * root;
});
}
// because if 2 * bar threw an error, this function would throw an error,
// but the other functions would return a rejected promise.
@twobiers
Copy link

twobiers commented Apr 11, 2022

This is not exactly the truth. An async function will be executed in sync until it is converted into a Promise by reaching a return or throw statement or the execution is suspendend when a await is reached.
In "reality" it would look like this:

function getFoo (bar) {
  // Notice that exceptions thrown in the promise constructor will be converted into a Promise rejection automatically
  return new Promise((resolve, reject) => {
    const baz = 2 * bar;
    // or maybe return asyncSqrt(baz);, but however you can also await non-promises. This ensures a promise will be resolved
    return resolve(asyncSqrt(baz)); 
  })
  .then(root => {
    return 2 * root;
  });
}

You can verify this behaviour by executing the following example:

async function testSynchronousCalls() {
  console.log("Executed in sync");
  return Promise.resolve("Executed async");
}

console.log("Started in sync");
testSynchronousCalls()
  .then(res => console.log(res));
console.log("Ended in sync");

@joeytwiddle
Copy link
Author

Thank you for the clarification Tobi. Perhaps I should have written "is basically equivalent to" instead of "is the same as".

Technically, using Promise.resolve().then() in my example is unnecessary, but I like to use it to start a promise chain, so we can forget about the need to call the resolve() or reject() callbacks. While less efficient for the engine, I think this reduces cognitive load. Since we may have a chain of many .then()s, I like to make the first code block the same as the rest.

Of course new Promise((resolve, reject) => ...) is highly suitable for converting callback-style functions into promises, but I don't really enjoy using it to start a promise chain in business logic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment