Repository navigation
Expand file tree
/
Copy pathindex.md
More file actions
196 lines (142 loc) · 6.82 KB
/
Copy pathindex.md
File metadata and controls
196 lines (142 loc) · 6.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
---
title: Promise.try()
short-title: try()
slug: Web/JavaScript/Reference/Global_Objects/Promise/try
page-type: javascript-static-method
browser-compat: javascript.builtins.Promise.try
sidebar: jsref
---
The **`Promise.try()`** static method takes a callback of any kind (returns or throws, synchronously or asynchronously) and [resolves](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve) its result to a {{jsxref("Promise")}}.
## Syntax
```js-nolint
Promise.try(func)
Promise.try(func, arg1)
Promise.try(func, arg1, arg2)
Promise.try(func, arg1, arg2, /* …, */ argN)
```
### Parameters
- `func`
- : A function that is called synchronously with the arguments provided (`arg1`, `arg2`, …, `argN`). It can do anything—either return a value, throw an error, or return a promise.
- `arg1`, `arg2`, …, `argN`
- : Arguments to pass to `func`.
### 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. The returned value is [resolved](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve) to a promise, which means built-in {{jsxref("Promise")}} objects are returned as-is.
## 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.
You can wrap this expression in `try...catch`:
```js
let result;
try {
result = Promise.resolve(func());
} catch (error) {
result = Promise.reject(error);
}
```
The problem is that `try...catch` is not an expression, so you can't directly use it in expression positions like passing it to other functions.
Therefore, when lifting a function call result into a promise, fulfilled or rejected, people more commonly do this:
```js
new Promise((resolve) => resolve(func()));
```
For the built-in `Promise()` constructor, errors thrown from the executor are automatically caught and turned into rejections, so this also prevents synchronous errors. The problem is that it unconditionally creates a new `Promise` object, which is unnecessary if `func()` already returns a `Promise`. `Promise.resolve()`, on the other hand, is smart enough to prevent that extra promise wrapping.
`Promise.try()` is almost exactly equivalent to the `try...catch` approach, except that it's shorter and can be used as an expression:
```js
Promise.try(func);
```
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.
Like {{domxref("Window/setTimeout", "setTimeout()")}}, `Promise.try()` accepts extra arguments that are passed to the callback. This means instead of doing this:
```js
Promise.try(() => func(arg1, arg2));
```
You can do this:
```js
Promise.try(func, arg1, arg2);
```
Which are equivalent, but the latter avoids creating an extra closure and is more efficient.
`Promise.try()` is generic and supports subclassing, which means it can be called on subclasses of `Promise`, and the result will contain 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.
## 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.
The following is a slightly more faithful approximation of the actual `Promise.try()` (although it should still not be used as a polyfill):
```js
Promise.try = function (func, ...args) {
let result;
try {
result = func(...args);
} catch (error) {
return Promise.reject.call(this, error);
}
return Promise.resolve.call(this, result);
};
```
`Promise.try()` delegates to {{jsxref("Promise.resolve()")}} and {{jsxref("Promise.reject()")}} to create the return value, and both of these functions are generic.
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),
);
}
static try = Promise.try;
}
const p = NotPromise.try(() => "hello");
// Logs: Resolved hello
// p is a NotPromise instance
const p2 = NotPromise.try(() => {
throw new Error("oops");
});
// Logs: Rejected Error: oops
// p2 is a NotPromise instance
```
## Specifications
{{Specifications}}
## Browser compatibility
{{Compat}}
## See also
- [Polyfill of `Promise.try` in `core-js`](https://github.com/zloirock/core-js#promisetry)
- [es-shims polyfill of `Promise.try`](https://www.npmjs.com/package/promise.try)
- [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)