@@ -9,6 +9,7 @@ ECMAScript Stage-2 Proposal. J. S. Choi, 2021.
9
9
[ specification ] : https://tc39.es/proposal-array-from-async/
10
10
[ core-js ] : https://github.com/zloirock/core-js#arrayfromasync
11
11
[ array-from-async ] : https://www.npmjs.com/package/array-from-async
12
+ [ § Errors ] : #errors
12
13
13
14
## Why an Array.fromAsync method
14
15
Since its standardization in JavaScript, ** [ Array.from] [ ] ** has become one of
@@ -102,6 +103,12 @@ for await (const v of genPromises(4)) {
102
103
const arr = await Array .fromAsync (genPromises (4 ));
103
104
```
104
105
106
+ Also like ` for await ` , when given a sync-but-not-async iterable input, then
107
+ Array.fromAsync ** will not handle** any yielded promises that ** reject** .
108
+ This is because ` Array.fromAsync ` ** lazily** iterates over its input, so it
109
+ cannot attach any handlers to its input’s promise values. For more information,
110
+ see [ § Errors] [ ] .
111
+
105
112
### Non-iterable array-like inputs
106
113
Array.fromAsync’s valid inputs are a superset of Array.from’s valid inputs. This
107
114
includes non-iterable array-likes: objects that have a length property as well
@@ -134,6 +141,11 @@ for await (const v of Array.from(arrLike)) {
134
141
const arr = await Array .fromAsync (arrLike);
135
142
```
136
143
144
+ As with sync iterables, when given a non-iterable input, then Array.fromAsync
145
+ ** will not handle** any yielded promises that ** reject** . This is because
146
+ ` Array.fromAsync ` ** lazily** iterates over its input, so it cannot attach any
147
+ handlers to its input’s promise values. For more information, see [ § Errors] [ ] .
148
+
137
149
### Generic factory method
138
150
Array.fromAsync is a generic factory method. It does not require that its this
139
151
receiver be the Array constructor. fromAsync can be transferred to or inherited
@@ -235,20 +247,95 @@ rejected, then Array.fromAsync’s returned promise will reject with that error.
235
247
236
248
``` js
237
249
const err = new Error ;
238
- function * genRejection () { yield Promise .reject (err); }
250
+ const rejection = Promise .reject (err);
251
+ function * genZeroThenRejection () {
252
+ yield 0 ;
253
+ yield rejection;
254
+ }
239
255
240
- // This creates a promise that will reject with `err`.
241
- Array .fromAsync (genRejection ());
256
+ // This creates a promise that will reject with `err`. However, `rejection`
257
+ // itself will not be handled by Array.fromAsync.
258
+ Array .fromAsync (genZeroThenRejection ());
242
259
```
243
260
244
261
``` js
245
262
const err = new Error ;
246
- const arrLikeWithRejection = { length: 1 , 0 : Promise .reject (err) };
263
+ const arrLikeWithRejection = {
264
+ length: 2 ,
265
+ 0 : 0 ,
266
+ 1 : Promise .reject (err),
267
+ };
247
268
248
269
// This creates a promise that will reject with `err`.
249
270
Array .fromAsync (arrLikeWithRejection);
250
271
```
251
272
273
+ However, like ` for await ` , in this case Array.fromAsync ** will not handle** any
274
+ yielded rejecting promises. This is because ` Array.fromAsync ` ** lazily**
275
+ iterates over its input, so it cannot attach any handlers to its input’s promise
276
+ values.
277
+
278
+ The creator of the rejecting promise is expected to synchronously attach a
279
+ rejection handler when the promise is created, as usual:
280
+
281
+ ``` js
282
+ const err = new Error ;
283
+ // The creator of the rejecting promise attaches a rejection handler.
284
+ const rejection = Promise .reject (err).catch (console .error );
285
+ function * genZeroThenRejection () {
286
+ yield 0 ;
287
+ yield rejection;
288
+ }
289
+
290
+ // This still creates a promise that will reject with `err`. `err` will also
291
+ // separately be printed to the console due to the rejection handler.
292
+ Array .fromAsync (genZeroThenRejection ());
293
+ ```
294
+
295
+ ``` js
296
+ const err = new Error ;
297
+ const arrLikeWithRejection = {
298
+ length: 2 ,
299
+ 0 : 0 ,
300
+ 1 : Promise .reject (err),
301
+ };
302
+
303
+ // This still creates a promise that will reject with `err`. `err` will also
304
+ // separately be printed to the console due to the rejection handler.
305
+ Array .fromAsync (arrLikeWithRejection);
306
+ ```
307
+
308
+ Alternatively, the user of the promises can switch from Array.fromAsync to
309
+ Promise.all. Promise.all would change the control flow from lazy sync iteration
310
+ (with sequential awaiting) to eager sync iteration (with parallel awaiting),
311
+ allowing the handling of any rejection in the input.
312
+
313
+ ``` js
314
+ const err = new Error ;
315
+ const rejection = Promise .reject (err);
316
+ function * genZeroThenRejection () {
317
+ yield 0 ;
318
+ yield rejection;
319
+ }
320
+
321
+ // Creates a promise that will reject with `err`. Unlike Array.fromAsync,
322
+ // Promise.all will handle the `rejection`.
323
+ Promise .all (genZeroThenRejection ());
324
+ ```
325
+
326
+ ``` js
327
+ const err = new Error ;
328
+ const arrLikeWithRejection = {
329
+ length: 2 ,
330
+ 0 : 0 ,
331
+ 1 : Promise .reject (err),
332
+ };
333
+
334
+ // Creates a promise that will reject with `err`. Unlike Array.fromAsync,
335
+ // Promise.all will handle the `rejection`.
336
+ Promise .all (Array .from (arrLikeWithRejection));
337
+ ```
338
+
252
339
If Array.fromAsync’s input has at least one value, and Array.fromAsync’s mapping
253
340
callback throws an error when given any of those values, then Array.fromAsync’s
254
341
returned promise will reject with the first such error.
0 commit comments