# Async collection methods

**URL:** <https://es.discourse.group/t/async-collection-methods/2078>\
**Category:** 🦋 Proposals\
**Tags:** proposal\
**Created:** [June 26, 2024, 12:55pm UTC](https://es.discourse.group/t/async-collection-methods/2078 "2024-06-26T12:55:52Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![GlenTiki](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/glentiki/32/2135_2.png) [@GlenTiki](https://es.discourse.group/u/GlenTiki)\
**Post date:** [June 26, 2024, 12:55pm UTC](https://es.discourse.group/t/async-collection-methods/2078/1 "2024-06-26T12:55:52Z")

</div>

**Proposal: Asynchronous Array Methods**  
_GitHub Proposal Link: [tc39/proposal-{{name-here}}](https://github.com/tc39/proposal-%60%7B%7Bname-here%7D%7D%60)_

## Introduction

A prevalent pattern in modern JavaScript involves transforming arrays into arrays of promises to handle asynchronous operations effectively. Consider the following common pattern:

```javascript
const array2 = await Promise.all(array1.map(asyncFn));

```

While this pattern works well with `map()`, it doesn't extend easily to other Array methods like `filter()`, `every()`, or `some()` when asynchronous predicates are involved. This leads to cumbersome and less intuitive workarounds.

### Terminology

- **Collection Functions** : Methods on the Array object that use a callback to manipulate data, e.g., `Array.filter`, `Array.map`.
- **Predicate** : The callback function used in collection methods.

## Motivation

Here are some current ways to handle asynchronous predicates in array methods:

**Verbose Async Filtering:**

```javascript
const filteredAsync = await Promise.all(array.map(async (item) => {
  const keep = await asyncPredicate(item);
  return keep ? item : null; // null or a sentinel value for filtering.
})).filter(item => item != null);

```

**Synchronous Loop with Asynchronous Checks:**

```javascript
const results = [];
for (let item of array) {
  if (await asyncPredicate(item)) {
    results.push(item);
  }
}

```

## Proposed Ideas

I propose considering the following enhancements to improve handling asynchronous operations in Array methods:

**Idea 1: Automatic Promise Detection**

Detect when a predicate returns a Promise and adjust the method’s return type to Promise, affecting its behavior.

_Example: Automatic Detection in `map()`_

```javascript
const array2 = await array1.map(asyncPredicate); // Detects async and awaits internally.

```

_Pros:_

- Intuitive and clean for new code bases.

_Cons:_

- Breaks existing expectations where an array of Promises is anticipated (e.g., `Promise.race()`).

**Idea 2: Optional Parameter for Async Mode**

Introduce an additional parameter that specifies asynchronous operations without altering the signature of existing parameters, such as `thisArg`.

_Example: Optional Async Parameter in `filter()` with `thisArg`_

```javascript
const asyncFiltered = await array1.filter(asyncPredicate, null, { async: true });

```

_Pros:_

- Backward compatible.
- Does not alter the expected behavior of the `thisArg`.

_Cons:_

- Slightly more complex function signatures
- You can't anticipate the expected behaviour until after reading the async arg. In code where there may be a long and complex async function inlined to do something like filtering, this affects clarity.

**Idea 3: Dedicated Asynchronous Methods**

Add new asynchronous counterparts like `asyncMap`, `asyncFilter`, which inherently support asynchronous operations.

_Example: Dedicated Asynchronous `map()`_

```javascript
const processedArray = await array1.asyncMap(asyncPredicate);

```

_Pros:_

- Explicit and declarative.
- Avoids altering existing method behaviors.

_Cons:_

- Increases the API surface of Array.

## Conclusion

I lean towards **Idea 3** after consideration, as it offers clarity and backward compatibility. Whichever approach is chosen, It would be important to decide the most efficient asynchronous handling for each method, such as the parallel execution and cancellation mechanisms for predicates that no longer need evaluation.

Feel free to share your thoughts or suggest improvements to these proposals.

---

<div class="post-metadata">

**Author:** ![GlenTiki](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/glentiki/32/2135_2.png) [@GlenTiki](https://es.discourse.group/u/GlenTiki)\
**Post date:** [June 26, 2024, 12:58pm UTC](https://es.discourse.group/t/async-collection-methods/2078/2 "2024-06-26T12:58:09Z")

</div>

Nevermind this, I can see [GitHub - tc39/proposal-async-iterator-helpers: Methods for working with async iterators in ECMAScript](https://github.com/tc39/proposal-async-iterator-helpers) would resolve the issue!

---

<div class="post-metadata">

**Author:** ![senocular](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/senocular/32/642_2.png) [@senocular](https://es.discourse.group/u/senocular)\
**Post date:** [June 26, 2024, 4:29pm UTC](https://es.discourse.group/t/async-collection-methods/2078/3 "2024-06-26T16:29:34Z")

</div>

This also seems related

> **[GitHub - tc39/proposal-await.ops: Introduce await.all / await.race /...](https://github.com/tc39/proposal-await.ops)**
>
> Introduce await.all / await.race / await.allSettled / await.any to simplify the usage of Promises - tc39/proposal-await.ops
