Skip to content

from() - Conversion depuis un tableau, une Promise, etc. ​

from() est une fonction de création qui crée un Observable à partir de tableaux, Promises, itérables et objets de type Observable.

Vue d'ensemble ​

from() convertit des structures de données existantes (tableaux, Promises, itérables, etc.) en flux Observable. En particulier, elle est fréquemment utilisée pour intégrer le traitement asynchrone (Promise) dans le monde RxJS.

Signature :

typescript
function from<T>(input: ObservableInput<T>, scheduler?: SchedulerLike): Observable<T>

Documentation officielle : 📘 RxJS Official : from()

Utilisation de base ​

from() accepte une variété de types d'entrée.

typescript
import { from } from 'rxjs';

// Créer à partir d'un tableau
const array$ = from([1, 2, 3]);
array$.subscribe({
  next: value => console.log('Valeur du tableau:', value),
  complete: () => console.log('Tableau terminé')
});

// Créer à partir d'une Promise
const promise$ = from(Promise.resolve('Résultat de la Promise'));
promise$.subscribe({
  next: value => console.log('Résultat de la Promise:', value),
  complete: () => console.log('Promise terminée')
});

// Créer à partir d'un itérable
const iterable$ = from(new Set([1, 2, 3]));
iterable$.subscribe({
  next: value => console.log('Valeur de l\'itérable:', value),
  complete: () => console.log('Itérable terminé')
});

// Sortie:
// Valeur du tableau: 1
// Valeur du tableau: 2
// Valeur du tableau: 3
// Tableau terminé
// Valeur de l'itérable: 1
// Valeur de l'itérable: 2
// Valeur de l'itérable: 3
// Itérable terminé
// Résultat de la Promise: Résultat de la Promise
// Promise terminée

Caractéristiques importantes ​

1. Émettre chaque élément du tableau individuellement ​

Lorsque from() reçoit un tableau, elle émet chaque élément du tableau individuellement dans l'ordre.

typescript
import { from } from 'rxjs';

from([10, 20, 30]).subscribe(value => console.log(value));

// Sortie:
// 10
// 20
// 30

IMPORTANT

Différence avec of() :

  • of([1, 2, 3]) → Émet le tableau lui-même comme une seule valeur
  • from([1, 2, 3]) → Émet chaque élément 1, 2, 3 séparément

2. Traitement automatique des Promises ​

Passer une Promise émettra la valeur résolue et se terminera immédiatement.

typescript
import { from } from 'rxjs';

const fetchData = (): Promise<string> => {
  return new Promise(resolve => {
    setTimeout(() => resolve('Récupération des données terminée'), 1000);
  });
};

from(fetchData()).subscribe({
  next: value => console.log(value),
  complete: () => console.log('Terminé')
});

// Sortie après 1 seconde:
// Récupération des données terminée
// Terminé

WARNING

Si la Promise est rejetée, l'Observable émet une erreur.

typescript
import { from } from "rxjs";
from(Promise.reject('Erreur')).subscribe({
  error: err => console.error('Erreur survenue:', err)
});

3. Prise en charge des itérables ​

En plus des tableaux, elle prend en charge les objets itérables tels que Set, Map et Generator.

typescript
import { from } from 'rxjs';

// Set
from(new Set(['A', 'B', 'C'])).subscribe(console.log);
// Sortie: A, B, C

// Map (paires clé-valeur)
from(new Map([['clé1', 'valeur1'], ['clé2', 'valeur2']])).subscribe(console.log);
// Sortie: ['clé1', 'valeur1'], ['clé2', 'valeur2']

// Generator
function* numberGenerator() {
  yield 1;
  yield 2;
  yield 3;
}
from(numberGenerator()).subscribe(console.log);
// Sortie: 1, 2, 3

4. Cold Observable ​

from() est un Cold Observable. Chaque abonnement initie une exécution indépendante.

typescript
import { from } from 'rxjs';

const numbers$ = from([1, 2, 3]);

numbers$.subscribe(val => console.log('Abonné A:', val));
numbers$.subscribe(val => console.log('Abonné B:', val));

// Chaque abonné traite le tableau indépendamment
// Sortie:
// Abonné A: 1
// Abonné A: 2
// Abonné A: 3
// Abonné B: 1
// Abonné B: 2
// Abonné B: 3

NOTE

Caractéristiques du Cold Observable :

  • Une exécution indépendante est initiée pour chaque abonnement
  • Chaque abonné reçoit son propre flux de données
  • Les Promises sont également évaluées par abonnement

Voir Cold Observable et Hot Observable pour plus d'informations.

Différence entre from() et of() ​

La différence la plus importante entre les deux est la façon dont les tableaux sont traités.

typescript
import { from, of } from 'rxjs';

const array = [1, 2, 3];

// of() - émet le tableau comme une seule valeur
of(array).subscribe(value => {
  console.log('of():', value); // [1, 2, 3]
});

// from() - émet chaque élément du tableau individuellement
from(array).subscribe(value => {
  console.log('from():', value); // 1, 2, 3
});
Fonction de créationTraitement du tableauObjectif
of([1, 2, 3])Émet le tableau lui-mêmeVeut traiter le tableau comme donnée
from([1, 2, 3])Émet chaque élément individuellementVeut traiter les éléments un par un

Cas d'utilisation pratiques ​

1. Streamer les appels API ​

Streamer les clients HTTP basés sur Promise comme Fetch API et axios.

typescript
import { from, Observable, of } from 'rxjs';
import { catchError } from 'rxjs';

interface User {
  id: number;
  name: string;
  email: string;
}

function fetchUser(id: number): Observable<User> {
  return from(
    fetch(`https://jsonplaceholder.typicode.com/users/${id}`)
      .then(response => response.json())
  ).pipe(
    catchError((error: unknown) => {
      console.error('Erreur API:', error);
      return of({ id: 0, name: 'Inconnu', email: '' });
    })
  );
}

fetchUser(1).subscribe(user => console.log('Utilisateur:', user));

2. Traitement séquentiel des éléments d'un tableau ​

Exécuter un traitement asynchrone de manière séquentielle pour chaque élément du tableau.

typescript
import { from } from 'rxjs';
import { concatMap, delay } from 'rxjs';

const urls = [
  'https://jsonplaceholder.typicode.com/posts/1',
  'https://jsonplaceholder.typicode.com/posts/2',
  'https://jsonplaceholder.typicode.com/posts/3'
];

from(urls).pipe(
  concatMap(url =>
    from(fetch(url).then(res => res.json())).pipe(
      delay(500) // Limitation du débit
    )
  )
).subscribe(data => console.log('Récupéré:', data));

3. Traitement d'itérateurs asynchrones ​

Les itérateurs asynchrones (générateurs async) sont également pris en charge.

typescript
import { from } from 'rxjs';

async function* asyncGenerator() {
  yield await Promise.resolve(1);
  yield await Promise.resolve(2);
  yield await Promise.resolve(3);
}

from(asyncGenerator()).subscribe(value => console.log(value));
// Sortie: 1, 2, 3

4. Intégration d'émetteurs d'événements ​

Streamer Node.js EventEmitter et les systèmes d'événements personnalisés.

typescript
import { from } from 'rxjs';

// Objet personnalisé itérable
class DataSource {
  *[Symbol.iterator]() {
    yield 'Donnée A';
    yield 'Donnée B';
    yield 'Donnée C';
  }
}

from(new DataSource()).subscribe(console.log);
// Sortie: Donnée A, Donnée B, Donnée C

Utilisation dans un pipeline ​

from() est utile pour utiliser des données existantes comme point de départ d'un traitement en pipeline.

typescript
import { from } from 'rxjs';
import { map, filter, reduce } from 'rxjs';

interface Product {
  id: number;
  name: string;
  price: number;
}

const products: Product[] = [
  { id: 1, name: 'Produit A', price: 1000 },
  { id: 2, name: 'Produit B', price: 2000 },
  { id: 3, name: 'Produit C', price: 500 }
];

from(products).pipe(
  filter(product => product.price >= 1000),
  map(product => product.price),
  reduce((sum, price) => sum + price, 0)
).subscribe(total => console.log('Montant total:', total));
// Sortie: Montant total: 3000

Erreurs courantes ​

1. Mauvaise compréhension du timing d'exécution de la Promise ​

typescript
// ❌ Incorrect - La Promise commence à s'exécuter à la création
const promise = fetch('https://jsonplaceholder.typicode.com/posts/1'); // Déjà démarrée
from(promise).subscribe(console.log); // Pas au moment de l'abonnement

// ✅ Correct - utiliser defer() si vous voulez exécuter à l'abonnement
import { defer, from } from 'rxjs';

const deferred$ = defer(() =>
  from(fetch('https://jsonplaceholder.typicode.com/posts/1'))
);
deferred$.subscribe(console.log); // S'exécute au moment de l'abonnement

WARNING

La Promise n'est pas évaluée paresseusement

La Promise commence à s'exécuter lorsqu'elle est créée. from(promise) ne fait qu'envelopper une Promise déjà en cours d'exécution. Si vous voulez l'exécuter au moment de l'abonnement, utilisez defer(() => from(promise)).

2. Confusion entre tableau et of() ​

typescript
import { from, map, of } from "rxjs";

// ❌ Différent de l'intention - le tableau entier est émis
of([1, 2, 3]).pipe(
  map(n => n * 2)
).subscribe(console.log);
// Sortie: [1, 2, 3] (le tableau lui-même)

// ✅ Correct - traiter chaque élément individuellement
from([1, 2, 3]).pipe(
  map(n => n * 2)
).subscribe(console.log);
// Sortie: 2, 4, 6

Considérations sur les performances ​

Les performances de from() dépendent du type d'entrée.

TIP

Conseils d'optimisation :

  • Lors du traitement de grandes quantités de données (des milliers à des dizaines de milliers d'éléments), limitez le nombre d'opérations simultanées lors de la combinaison avec concatMap et mergeMap.
  • Lors du traitement de tableaux de Promises, envisagez d'utiliser forkJoin ou combineLatest.
typescript
import { from } from 'rxjs';
import { mergeMap } from 'rxjs';

const urls = [...Array(100)].map((_, i) => `https://jsonplaceholder.typicode.com/posts/${i + 1}`);

from(urls).pipe(
  mergeMap(
    url => from(fetch(url).then(res => res.json())),
    5 // Limiter l'exécution simultanée à 5
  )
).subscribe(data => console.log(data));

Fonctions de création associées ​

FonctionDifférenceUtilisation
of()Émet les arguments en séquenceVeut émettre les valeurs telles quelles
fromEvent()Streamer les événementsGérer les événements DOM ou EventEmitter
defer()Différer la génération jusqu'à l'abonnementBesoin d'exécution paresseuse de Promise
ajax()Dédié à la communication HTTPVeut compléter les requêtes HTTP dans RxJS

Résumé ​

  • from() crée un Observable à partir de tableaux, Promises et itérables
  • Émet chaque élément d'un tableau séparément (différent de of())
  • Traite automatiquement la Promise et émet le résultat
  • Idéal pour intégrer le traitement asynchrone dans le monde RxJS
  • Notez que la Promise est exécutée au moment de la création (utilisez defer() pour une exécution paresseuse)

Prochaines étapes ​

Publié sous licence CC-BY-4.0.