# Allow "awaiting" on arrays

**URL:** <https://es.discourse.group/t/allow-awaiting-on-arrays/178>\
**Category:** 💡 Ideas\
**Tags:** proposal\
**Created:** [December 31, 2019, 2:06am UTC](https://es.discourse.group/t/allow-awaiting-on-arrays/178 "2019-12-31T02:06:53Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![mazyvan](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/mazyvan/32/199_2.png) [@mazyvan](https://es.discourse.group/u/mazyvan)\
**Post date:** [December 31, 2019, 2:06am UTC](https://es.discourse.group/t/allow-awaiting-on-arrays/178/1 "2019-12-31T02:06:53Z")

</div>

## Abstract

Just like we can make use of the `await` on `async` functions. I suggest what I think is really simple, but very useful as well. A new way to `await` over an array of promises.  
A syntactic sugar for the old `Promise.all()`

## The problem (AKA current implementation)

It's not uncommon to have something like this all across our code:

```javascript
function getUser(id) {
  return userStore.getById(id);
}

async function loadUsers(ids) {
  const usersPromisesQueue = ids.map(async id => await getUser(id)); // usersPromisesQueue is now an array of promises that must be awaited
  const users = await Promises.all(usersPromisesQueue);

  return users;
}

```

Or you could say that I could simplify that as follow:

```javascript
function loadUsers(ids) {
  return Promises.all(ids.map(getUser));
}

```

But I suggest to make arrays "thenables" by default allowing us to just `await` on them.

Because if you go with the first implementation, what is the better name for a `usersPromisesQueue`?

## Proposal

Just like an async function is just a syntactic sugar for a Promise. What about making `await` over an array a syntactic sugar for the `Promise.all()`. The exact same behavior.

So that our code could look just like:

```javascript
async function loadUsers(ids) {
  const users = await ids.map(async id => await getUser(id)); // notice the await directly executed over the result of the .map (an Array)
}

```

Or even better. What about:

```javascript
function loadUsers(ids) {
  return ids.map(getUser);
}

async function loadContext(usersIds, ...moreStuff) {
  const users = await loadUsers(usersIds); // since the return of the loadUsers() function is an array. We could simply await on it.

  // ... more stuff here
}

```

And the Polyfill for this will be pretty easy.

For me, this makes total sense. Because it makes the code a lot more readable.

So, I would like you guys to leve some comments. And PLMK what do you think 😊

---

<div class="post-metadata">

**Author:** ![claudiameadows](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/claudiameadows/32/126_2.png) [@claudiameadows](https://es.discourse.group/u/claudiameadows)\
**Post date:** [December 31, 2019, 6:13am UTC](https://es.discourse.group/t/allow-awaiting-on-arrays/178/2 "2019-12-31T06:13:38Z")

</div>

What if the array is just an array of objects that happen to have `.then` methods but don't follow the thenable protocol? Also, there's a valid use case for returning arrays of promises without flattening them - you might want to chain the inner promises separately for whatever reason (think: tasks and such).

Pretty sure this would also be web-incompatible to boot, but I have neither numbers nor access to the tools to verify that claim.

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [December 31, 2019, 6:23am UTC](https://es.discourse.group/t/allow-awaiting-on-arrays/178/3 "2019-12-31T06:23:11Z")

</div>

To make this work, you’d have to have Array.prototype.then defined; this would immediately destroy any website that used a promise for an array.

---

<div class="post-metadata">

**Author:** ![Alexsey](https://avatars.discourse-cdn.com/v4/letter/a/f19dbf/32.png) [@Alexsey](https://es.discourse.group/u/Alexsey)\
**Post date:** [December 31, 2019, 10:34am UTC](https://es.discourse.group/t/allow-awaiting-on-arrays/178/4 "2019-12-31T10:34:48Z")

</div>

And what if it would be a different operator, lets name it for now `dawait` for "deep await" that would await not only for emidiate operand to be resolved but for any deep property of resolved operand to be resolved as well? So it would work for arrays of promises, objects of promises etc.?

---

<div class="post-metadata">

**Author:** ![mazyvan](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/mazyvan/32/199_2.png) [@mazyvan](https://es.discourse.group/u/mazyvan)\
**Post date:** [January 1, 2020, 2:44am UTC](https://es.discourse.group/t/allow-awaiting-on-arrays/178/5 "2020-01-01T02:44:57Z")

</div>

> [@claudiameadows](#):
>
> What if the array is just an array of objects that happen to have `.then` methods but don't follow the thenable protocol?

Well, the result should be the same that what happens with the `Promise.all()` method. This must be just a simplified way to do it.

> [@claudiameadows](#):
>
> Also, there's a valid use case for returning arrays of promises without flattening them

This implementation does not force you to always flat your arrays of promises. You should be able to just return arrays of promises as always and manipulate them as usual.

---

<div class="post-metadata">

**Author:** ![mazyvan](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/mazyvan/32/199_2.png) [@mazyvan](https://es.discourse.group/u/mazyvan)\
**Post date:** [January 1, 2020, 2:56am UTC](https://es.discourse.group/t/allow-awaiting-on-arrays/178/6 "2020-01-01T02:56:06Z")

</div>

Absolutely.  
The whole idea around this, is to define and standardize the `Array.prototype.then`

Perhaps a little bit more complex if we want to make "thenable" any kind of iterator.

What I'm questioning with this is the necessity of `Promise.all()` by itself (for arrays of promises).  
If `Array.prototype.then` is not defined yet, what stop us to define this behavior?

```javascript
const array = [];
array.then(result => {
  console.log(result);
})

```

This ↑ has a lot more sense to me.

---

<div class="post-metadata">

**Author:** ![mazyvan](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/mazyvan/32/199_2.png) [@mazyvan](https://es.discourse.group/u/mazyvan)\
**Post date:** [January 1, 2020, 2:59am UTC](https://es.discourse.group/t/allow-awaiting-on-arrays/178/7 "2020-01-01T02:59:25Z")

</div>

> [@ljharb](#):
>
> this would immediately destroy any website that used a promise for an array.

Not sure if I get it. Could you explain this to me?

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [January 1, 2020, 6:34am UTC](https://es.discourse.group/t/allow-awaiting-on-arrays/178/8 "2020-01-01T06:34:58Z")

</div>

Well, for one, Promise.all already returns a promise for an array. This means array can never ever be thenable, or every usage of Promise.all would break (it would also mean that “what Would Array.prototype.then produce a Promise for” be unanswerable).

---

<div class="post-metadata">

**Author:** ![Jonas\_Wilms](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/jonas_wilms/32/189_2.png) [@Jonas\_Wilms](https://es.discourse.group/u/Jonas_Wilms)\
**Post date:** [January 2, 2020, 5:44pm UTC](https://es.discourse.group/t/allow-awaiting-on-arrays/178/9 "2020-01-02T17:44:43Z")

</div>

I generally like the idea of making it easier to work with an array of Promises, but I don't think this should be implemented for arrays in general.

The main point against `Array.prototype.then` for me is that returning a regular array, let's say with a few million elements from an async function (or resolving a promise with it), would then cause the whole array to be checked wether one of the elements contains a thenable. That's a major performance for a little benefit.

I'd rather propose something along the lines of:

```
  class AsyncArray extends Array {
     then(resolve, reject) {
        Promise.all(this).then(resolve, reject);
     }
  }

  // usage:
  await new AsyncArray(1, 2, 3).map(async n => n)
```

---

<div class="post-metadata">

**Author:** ![mazyvan](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/mazyvan/32/199_2.png) [@mazyvan](https://es.discourse.group/u/mazyvan)\
**Post date:** [January 6, 2020, 6:54pm UTC](https://es.discourse.group/t/allow-awaiting-on-arrays/178/10 "2020-01-06T18:54:05Z")

</div>

**Update**

I tried to make my own implementation (or polyfill) for this but I faced this interesting problem...

> <https://stackoverflow.com/questions/59615739/why-does-promise-all-tigger-array-prototype-then-if-defined>

So it fail. But for a different reason.

---

<div class="post-metadata">

**Author:** ![jridgewell](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/jridgewell/32/18_2.png) [@jridgewell](https://es.discourse.group/u/jridgewell)\
**Post date:** [January 16, 2020, 11:36pm UTC](https://es.discourse.group/t/allow-awaiting-on-arrays/178/11 "2020-01-16T23:36:14Z")

</div>

Didn't we have `await *` for exactly this?

---

<div class="post-metadata">

**Author:** ![JackWorks](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/jackworks/32/260_2.png) [@JackWorks](https://es.discourse.group/u/JackWorks)\
**Post date:** [March 1, 2020, 11:09am UTC](https://es.discourse.group/t/allow-awaiting-on-arrays/178/12 "2020-03-01T11:09:24Z")

</div>

I wrote a polyfill for it before. But the solution is quite hacky (and might be buggy in nestted await or `finally` block).

DONT USE IT!!!! I have a better version on post #16 [Allow "awaiting" on arrays](https://es.discourse.group/t/allow-awaiting-on-arrays/178/16)

```javascript
// DONT USE IT
Array.prototype.then = function x(resolve, reject) {
    Array.prototype.then = undefined
    const restore = f => value => {
        const result = typeof f === 'function' ? f(value) : value
        Array.prototype.then = x
        if (f === reject && typeof f === 'function') return Promise.reject(value)
        return result
    }
    return Promise.all(this).then(restore(resolve), restore(reject))
}

```

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [March 2, 2020, 10:08pm UTC](https://es.discourse.group/t/allow-awaiting-on-arrays/178/13 "2020-03-02T22:08:25Z")

</div>

That seems like it would create the possibility that code could run in between the deletion and restoration of `Array.prototype.then`, causing it to break in unpredictable ways.

I would strongly caution everyone not to speculatively modify builtins, even in channels like this, since people often copy-paste code they find on the internet :-)

---

<div class="post-metadata">

**Author:** ![JackWorks](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/jackworks/32/260_2.png) [@JackWorks](https://es.discourse.group/u/JackWorks)\
**Post date:** [March 12, 2020, 1:56pm UTC](https://es.discourse.group/t/allow-awaiting-on-arrays/178/14 "2020-03-12T13:56:16Z")

</div>

A `await* expr` mentioned by @jridgewell looks good

---

<div class="post-metadata">

**Author:** ![JackWorks](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/jackworks/32/260_2.png) [@JackWorks](https://es.discourse.group/u/JackWorks)\
**Post date:** [March 13, 2020, 7:05am UTC](https://es.discourse.group/t/allow-awaiting-on-arrays/178/15 "2020-03-13T07:05:57Z")

</div>

In another way, it's boring to write

```javascript
await Promise.all(arr.map(async () { ... }))

```

If there is a syntax sugar for it, things will be nicer

```javascript
for parallel await (const x of arr) {
    ...
}

```

---

<div class="post-metadata">

**Author:** ![JackWorks](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/jackworks/32/260_2.png) [@JackWorks](https://es.discourse.group/u/JackWorks)\
**Post date:** [May 27, 2020, 3:38am UTC](https://es.discourse.group/t/allow-awaiting-on-arrays/178/16 "2020-05-27T03:38:11Z")

</div>

I have a better polyfill now, it won't delete & restore the prototype @ljharb

Still, DONT USE IT IN YOUR PRODUCT

```javascript
Array.prototype.then = async function (resolve, reject) {
    class NonThenableArray extends Array {}
    NonThenableArray.prototype.then = 0
    NonThenableArray.prototype[Symbol.species] = NonThenableArray
    const result = new NonThenableArray()
    // This won't make promises parallel
    for (const p of this) {
        try { result.push(await p) }
        catch (e) { return reject(e) }
    }
    resolve(result)
}

```

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [May 27, 2020, 4:16am UTC](https://es.discourse.group/t/allow-awaiting-on-arrays/178/17 "2020-05-27T04:16:37Z")

</div>

Seems like you'd want `return Promise.allSettled(this)` as the entire invocation instead of needing NonThenableArray? Either way tho, it's still dangerous to have examples of code that mutates builtins; all it takes is enough websites using code that does it and we'd never be able to use the name :-)

---

<div class="post-metadata">

**Author:** ![JackWorks](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/jackworks/32/260_2.png) [@JackWorks](https://es.discourse.group/u/JackWorks)\
**Post date:** [May 27, 2020, 4:23am UTC](https://es.discourse.group/t/allow-awaiting-on-arrays/178/18 "2020-05-27T04:23:30Z")

</div>

Yeah. It's just an example, and I won't encourage anyone to use it seriously.

But the ergonomics of handling multiple async tasks is bad today. Does it considerable things like `await* array` or `for await* (const x of expr)`?

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [May 27, 2020, 4:35am UTC](https://es.discourse.group/t/allow-awaiting-on-arrays/178/19 "2020-05-27T04:35:39Z")

</div>

`await *` imo doesn't convey anything about what it's doing; if it's using Promise.all semantics, then what about `race`, `allSettled`, or `any`?

I could see an `await.all`/`await.race`/`await.allSettled`/`await.any`, though (with the implication that any new combinators would get the same support).

---

<div class="post-metadata">

**Author:** ![JackWorks](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/jackworks/32/260_2.png) [@JackWorks](https://es.discourse.group/u/JackWorks)\
**Post date:** [May 27, 2020, 4:49am UTC](https://es.discourse.group/t/allow-awaiting-on-arrays/178/20 "2020-05-27T04:49:12Z")

</div>

`await.all` / `await.race` / `await.allSettled` / `await.any`

Cool. What about making it a proposal?

(Upper case in the meta property look a bit strange)

[Next page](https://es.discourse.group/t/allow-awaiting-on-arrays/178.md?page=2)
