Skip to content

Commit

Permalink
Reference for stage 3 promise-try (#34929)
Browse files Browse the repository at this point in the history
  • Loading branch information
Josh-Cena authored Jul 19, 2024
1 parent b736420 commit 6515191
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,8 @@ Note that JavaScript is [single-threaded](/en-US/docs/Glossary/Thread) by nature
- : Returns a new `Promise` object that is rejected with the given reason.
- {{jsxref("Promise.resolve()")}}
- : Returns a `Promise` object that is resolved with the given value. If the value is a thenable (i.e. has a `then` method), the returned promise will "follow" that thenable, adopting its eventual state; otherwise, the returned promise will be fulfilled with the value.
- {{jsxref("Promise.try()")}}
- : Takes a callback of any kind (returns or throws, synchronously or asynchronously) and wraps its result in a `Promise`.
- {{jsxref("Promise.withResolvers()")}}
- : Returns an object containing a new `Promise` object and two functions to resolve or reject it, corresponding to the two parameters passed to the executor of the {{jsxref("Promise/Promise", "Promise()")}} constructor.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ A {{jsxref("Promise")}} that is resolved with the given value, or the promise pa

`Promise.resolve()` _resolves_ a promise, which is not the same as fulfilling or rejecting the promise. See [Promise description](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise#description) for definitions of the terminology. In brief, `Promise.resolve()` returns a promise whose eventual state depends on another promise, thenable object, or other value.

> **Note:** If evaluating the `value` expression may synchronously throw an error, this error won't be caught and wrapped in a rejected promise by `Promise.resolve()`. Consider using {{jsxref("Promise/try", "Promise.try(() => value)")}} in this case.
`Promise.resolve()` is generic and supports subclassing, which means it can be called on subclasses of `Promise`, and the result will be a promise of the subclass type. To do so, the subclass's constructor must implement the same signature as the [`Promise()`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise) constructor — accepting a single `executor` function that can be called with the `resolve` and `reject` callbacks as parameters.

`Promise.resolve()` special-cases native `Promise` instances. If `value` belongs to `Promise` or a subclass, and `value.constructor === Promise`, then `value` is directly returned by `Promise.resolve()`, without creating a new `Promise` instance. Otherwise, `Promise.resolve()` is essentially a shorthand for `new Promise((resolve) => resolve(value))`.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
---
title: Promise.try()
slug: Web/JavaScript/Reference/Global_Objects/Promise/try
page-type: javascript-static-method
browser-compat: javascript.builtins.Promise.try
---

{{JSRef}}

The **`Promise.try()`** static method takes a callback of any kind (returns or throws, synchronously or asynchronously) and wraps its result in a {{jsxref("Promise")}}.

## Syntax

```js-nolint
Promise.try(func)
```

### Parameters

- `func`
- : A function that is called synchronously with no arguments. It can do anything—either return a value, throw an error, or return a promise.

### Return value

A {{jsxref("Promise")}} that is:

- Already fulfilled, if `func` synchronously returns a value.
- Already rejected, if `func` synchronously throws an error.
- Asynchronously fulfilled or rejected, if `func` returns a promise.

## Description

You may have an API that takes a callback. The callback may be synchronous or asynchronous. You want to handle everything uniformly by wrapping the result in a promise. The most straightforward way might be {{jsxref("Promise/resolve", "Promise.resolve(func())")}}. The problem is that if `func()` synchronously throws an error, this error would not be caught and turned into a rejected promise. The correct way to do so is the following, which `Promise.try(func)` is exactly equivalent to:

```js
new Promise((resolve) => resolve(func()));
```

Except that `Promise.try()` is perhaps more concise and readable. To be more exact, the following is a more faithful representation of the implementation of `Promise.try()` (although it should still not be used as a polyfill):

```js
new Promise((resolve, reject) => {
try {
resolve(func());
} catch (error) {
reject(error);
}
});
```

For the built-in `Promise()` constructor, errors thrown from the executor are automatically caught and turned into rejections, so these two examples are equivalent.

Note that `Promise.try()` is _not_ equivalent to this, despite being highly similar:

```js
Promise.resolve().then(func);
```

The difference is that the callback passed to {{jsxref("Promise/then", "then()")}} is always called asynchronously, while the executor of the `Promise()` constructor is called synchronously. `Promise.try` also calls the function synchronously, and resolves the promise immediately if possible.

`Promise.try()`, combined with {{jsxref("Promise/catch", "catch()")}} and {{jsxref("Promise/finally", "finally()")}}, can be used to handle both synchronous and asynchronous errors in a single chain, and make promise error handling appear almost like synchronous error handling.

## Examples

### Using Promise.try()

The following example takes a callback, "lifts" it into a promise, handles the result, and does some error handling:

```js
function doSomething(action) {
return Promise.try(action)
.then((result) => console.log(result))
.catch((error) => console.error(error))
.finally(() => console.log("Done"));
}

doSomething(() => "Sync result");

doSomething(() => {
throw new Error("Sync error");
});

doSomething(async () => "Async result");

doSomething(async () => {
throw new Error("Async error");
});
```

In async/await, the same code would look like this:

```js
async function doSomething(action) {
try {
const result = await action();
console.log(result);
} catch (error) {
console.error(error);
} finally {
console.log("Done");
}
}
```

### Calling try() on a non-Promise constructor

`Promise.try()` is a generic method. It can be called on any constructor that implements the same signature as the `Promise()` constructor. For example, we can call it on a constructor that passes `console.log` as the `resolve` and `reject` functions to `executor`:

```js
class NotPromise {
constructor(executor) {
// The "resolve" and "reject" functions behave nothing like the native
// promise's, but Promise.try() just calls resolve
executor(
(value) => console.log("Resolved", value),
(reason) => console.log("Rejected", reason),
);
}
}

const p = Promise.try.call(NotPromise, () => "hello");
// Logs: Resolved hello

const p2 = Promise.try.call(NotPromise, () => {
throw new Error("oops");
});
// Logs: Rejected Error: oops
```

## Specifications

{{Specifications}}

## Browser compatibility

{{Compat}}

## See also

- [Polyfill of `Promise.try` in `core-js`](https://github.com/zloirock/core-js#promisetry)
- [Using promises](/en-US/docs/Web/JavaScript/Guide/Using_promises) guide
- {{jsxref("Promise")}}
- [`Promise()` constructor](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise)

0 comments on commit 6515191

Please sign in to comment.