3

Promise.try to improve error handling and sync/async interoperability

 1 week ago
source link: https://pawelgrzybek.com/promise-try-to-improve-error-handling-and-sync-async-interoperability/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Promise.try to improve error handling and sync/async interoperability

Published: 2024.04.09 · 3 minutes read

A few months ago, I published “Deferred JavaScript promises using Promise.withResolvers, which explains a modern way of dealing with one of the cumbersome chores as old as the Promises in JavaScript. Following the trend of adding to the specifications features that simplify our programs, today is about the upcoming Promise.try, which is quickly progressing through the ECMAScript proposals stages.

Assuming we have two functions, one that returns a promise and another one that synchronously returns a value, we can mix and match them like so:

const retSync = () => "sync return";
const retAsync = () => new Promise((r) => r("async return"));

(async () =>
  retAsync()
    .then(console.log)
    .then(retSync)
    .then(console.log)
    .catch(console.error))();

// async return
// sync return

Let’s flip the order and put a synchronous function first.

// 🚨 this is not going to work

const retSync = () => "sync return";
const retAsync = () => new Promise((r) => r("async return"));

(async () =>
  retSync()
    .then(console.log)
    .then(retAsync)
    .then(console.log)
    .catch(console.error))();

// TypeError: retSync().then is not a function. (In 'retSync().then(console.log)', 'retSync().then' is undefined)

We can’t do that because the return value of retSync is not a thenable promise. We need to wrap a synchronously returning function in a promise.

const retSync = () => "sync return";
const retAsync = () => new Promise((r) => r("async return"));

(async () =>
  Promise.resolve()
    .then(retSync)
    .then(console.log)
    .then(retAsync)
    .then(console.log)
    .catch(console.error))();

// sync return
// async return

That works, but we wasted an event-loop cycle. It’s doable to solve, though!

const retSync = () => "sync return";
const retAsync = () => new Promise((r) => r("async return"));

(async () =>
  new Promise((resolve) => resolve(retSync()))
    .then(console.log)
    .then(retAsync)
    .then(console.log)
    .catch(console.error))();

// sync return
// async return

Finally, but isn’t that tiresome? It would be cool to mix and match them without being concerned about whether a thing is synchronous or asynchronous. Also, a common catch clause is handy for handling errors in a single place, without writing error handling individually for sync and async executions.

There are plenty of solutions in the ecosystem already: p-try by Sindre Sorhus, Bluebird Promise.try/Promise.attempt or es6-promise-try, to name a few. Also, there is a native Promise.try progressing through the ECMAScript proposal stages, and I am sure it will be part of a language specification soon.

const retSync = () => "sync return";
const retAsync = () => new Promise((r) => r("async return"));

(async () =>
  Promise.try(retSync)
    .then(console.log)
    .then(retAsync)
    .then(console.log)
    .catch(console.error))();

// sync return
// async return

Hopefully, this post helped you to understand the purpose and what kind of problem Promise.try is trying to solve. Keep on coding and I will catch("you") next time 👋

Did you like it? Please share it with your friends. Thanks!

Leave a comment#

Name:
Website (optional):
GitHub (optional):
Comment:

👆 you can use Markdown here

Save my data for the next time I comment

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK