Nouveau dans JavaScript en 2024, le nouvel opérateur Array.fromAsync pourrait changer beaucoup de lignes de code dans vos projets.
La syntaxe
Inspiré de Array.from, Array.fromAsync permet la même chose pour des promesses.
// Au lieu de
const arr = []
for await (const item of asyncIterable) {
arr.push(item)
}
// arr contient maintenant tous les items de asyncIterable
// On peut maintenant écrire
const arr = await Array.fromAsync(asyncIterable)
Les avantages de Array.fromAsync
Et Promise.all() ?
On pourrait utiliser Promise.all pour résoudre les promesses dans un tableau. Le seul problème est que celles-ci sont exécutées au même moment. Avec fromAsync, l'exécution est séquentielle.
L'avantage principal de cette manière de procéder est d'éviter la surcharge mémoire et la surcharge API.
Comme avec Promise.all(), Array.fromAsync est rejeté si une des promesses l'est.
Array like et Set
Array.fromAsync permet quelques libertés, par exemple, passer un objet (array like), très utile pour itérer sur des retours API.
Array.fromAsync({
length: 3,
0: Promise.resolve(1),
1: Promise.resolve(2),
2: Promise.resolve(3),
}).then((array) => console.log(array));
// [1, 2, 3]
Ou avec des Set
Array.fromAsync(
new Set([Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)]),
).then((array) => console.log(array));
// [1, 2, 3]
Un inconvénient de Array.fromAsync
Dans le cas d'une exécution séquentielle, le temps d'exécution est forcément allongé, il faut donc le prendre en compte.
Application concrète
En programmation fonctionnelle, il est possible de créer des séquences d'exécution. Par exemple depuis fp-ts :
import * as E from 'fp-ts/lib/Either'
type RegisterInput = {
email: string
password: string
}
declare function validateEmail(email: string): E.Either
declare function validatePassword(password: string): E.Either
declare function register(input: RegisterInput): unknown
declare const input: RegisterInput
pipe(
input,
({ email, password }) =>
sequenceS(E.either)({
email: validateEmail(email),
password: validatePassword(password),
}),
E.map(register),
)
Il devient possible d'utiliser les séquences nativement grâce à cette nouvelle fonctionnalité.
Array.fromAsync([
Promise.resolve("foo"),
Promise.resolve(true),
Promise.resolve(false),
]).then(([promise1, promise2, promise3]) =>
console.log([promise1, promise2, promise3])
);
// ["foo", true, false]
Pour aller plus loin, il est possible, en utilisant les itérateurs, de pouvoir contrôler les valeurs passées de l'une à l'autre des itérations.
Comme à chaque nouvel ajout sur JavaScript, il faut prendre avec des pincettes et bien étudier les cas d'usage avant de l'implémenter dans son code.