Skip to content

delayWhen - Contrôle dynamique des délais ​

L'opérateur delayWhen détermine le temps de délai pour chaque valeur dynamiquement en utilisant des Observables individuels. Alors que l'opérateur delay fournit un délai fixe, delayWhen peut appliquer différents délais à chaque valeur.

🔰 Syntaxe et comportement de base ​

Spécifiez une fonction qui retourne un Observable pour déterminer le délai pour chaque valeur.

ts
import { of, timer } from 'rxjs';
import { delayWhen } from 'rxjs';

of('A', 'B', 'C')
  .pipe(
    delayWhen(value => {
      const delayTime = value === 'B' ? 2000 : 1000;
      return timer(delayTime);
    })
  )
  .subscribe(console.log);
// Sortie :
// A (après 1 seconde)
// C (après 1 seconde)
// B (après 2 secondes)

Dans cet exemple, seule la valeur 'B' a un délai de 2 secondes appliqué, tandis que les autres ont un délai de 1 seconde.

🌐 Documentation officielle RxJS - delayWhen

💡 Cas d'utilisation typiques ​

  • Délai basé sur la valeur : Modification du temps de délai selon la priorité ou le type
  • Délai par événement externe : Attente des actions utilisateur ou de l'achèvement d'autres flux
  • Délai conditionnel : Retarder uniquement des valeurs spécifiques
  • Contrôle du timing asynchrone : Attente des réponses API ou de la disponibilité des données

🧪 Exemple de code pratique 1 : Délai basé sur la priorité ​

Exemple contrôlant le timing de traitement selon la priorité des tâches.

ts
import { from, timer } from 'rxjs';
import { delayWhen } from 'rxjs';

// Création de l'interface utilisateur
const container = document.createElement('div');
document.body.appendChild(container);

const title = document.createElement('h3');
title.textContent = 'delayWhen - Délai basé sur la priorité';
container.appendChild(title);

const output = document.createElement('div');
output.style.border = '1px solid #ccc';
output.style.padding = '10px';
output.style.maxHeight = '300px';
output.style.overflow = 'auto';
container.appendChild(output);

interface Task {
  id: number;
  name: string;
  priority: 'high' | 'medium' | 'low';
}

const tasks: Task[] = [
  { id: 1, name: 'Tâche A', priority: 'low' },
  { id: 2, name: 'Tâche B', priority: 'high' },
  { id: 3, name: 'Tâche C', priority: 'medium' },
  { id: 4, name: 'Tâche D', priority: 'high' },
  { id: 5, name: 'Tâche E', priority: 'low' }
];

function addLog(message: string, color: string) {
  const logItem = document.createElement('div');
  logItem.style.padding = '5px';
  logItem.style.marginBottom = '3px';
  logItem.style.backgroundColor = color;

  const now = new Date();
  const time = now.toLocaleTimeString('fr-FR', { hour12: false }) +
    '.' + now.getMilliseconds().toString().padStart(3, '0');

  logItem.textContent = `[${time}] ${message}`;
  output.appendChild(logItem);
}

addLog('Début du traitement', '#e3f2fd');

from(tasks)
  .pipe(
    delayWhen(task => {
      // Définir le temps de délai selon la priorité
      let delayTime: number;
      switch (task.priority) {
        case 'high':
          delayTime = 500;  // Haute priorité : 0,5 seconde
          break;
        case 'medium':
          delayTime = 1500; // Priorité moyenne : 1,5 seconde
          break;
        case 'low':
          delayTime = 3000; // Basse priorité : 3 secondes
          break;
      }
      return timer(delayTime);
    })
  )
  .subscribe({
    next: task => {
      const colors = {
        high: '#c8e6c9',
        medium: '#fff9c4',
        low: '#ffccbc'
      };
      addLog(
        `${task.name} (priorité : ${task.priority}) traité`,
        colors[task.priority]
      );
    },
    complete: () => {
      addLog('Toutes les tâches sont terminées', '#e3f2fd');
    }
  });
  • Les tâches à haute priorité sont traitées après 0,5 seconde
  • Priorité moyenne après 1,5 seconde, basse priorité après 3 secondes
  • Réalise un ordre de traitement selon l'importance des tâches

🧪 Exemple de code pratique 2 : Délai par événement externe ​

Exemple attendant les clics de l'utilisateur avant d'émettre les valeurs.

ts
import { of, fromEvent } from 'rxjs';
import { delayWhen, take, tap } from 'rxjs';

// Création de l'interface utilisateur
const container2 = document.createElement('div');
container2.style.marginTop = '20px';
document.body.appendChild(container2);

const title2 = document.createElement('h3');
title2.textContent = 'delayWhen - Attente de clic';
container2.appendChild(title2);

const button = document.createElement('button');
button.textContent = 'Cliquez pour afficher la valeur suivante';
button.style.marginBottom = '10px';
container2.appendChild(button);

const output2 = document.createElement('div');
output2.style.border = '1px solid #ccc';
output2.style.padding = '10px';
output2.style.minHeight = '100px';
container2.appendChild(output2);

function addLog2(message: string) {
  const logItem = document.createElement('div');
  logItem.style.padding = '5px';
  logItem.style.marginBottom = '3px';
  logItem.textContent = message;
  output2.appendChild(logItem);
}

let clickCount = 0;

of('Message 1', 'Message 2', 'Message 3')
  .pipe(
    tap(msg => {
      addLog2(`En attente : ${msg} (cliquez sur le bouton)`);
      button.textContent = `Cliquez pour afficher « ${msg} »`;
    }),
    delayWhen(() => {
      // Délai jusqu'à ce qu'un événement de clic se produise
      return fromEvent(button, 'click').pipe(take(1));
    })
  )
  .subscribe({
    next: msg => {
      clickCount++;
      addLog2(`✅ Affiché : ${msg}`);
      if (clickCount < 3) {
        button.disabled = false;
      } else {
        button.textContent = 'Terminé';
        button.disabled = true;
      }
    },
    complete: () => {
      addLog2('--- Tous les messages ont été affichés ---');
    }
  });
  • Chaque valeur est émise après l'attente du clic de l'utilisateur
  • Contrôle de délai déclenché par des événements externes possible
  • Applicable au traitement de séquences interactives

🆚 Comparaison avec delay ​

ts
import { of, timer } from 'rxjs';
import { delay, delayWhen } from 'rxjs';

// delay - Délai à temps fixe
of(1, 2, 3)
  .pipe(delay(1000))
  .subscribe(console.log);
// Toutes les valeurs sont retardées de 1 seconde

// delayWhen - Délai différent par valeur
of(1, 2, 3)
  .pipe(
    delayWhen(value => timer(value * 1000))
  )
  .subscribe(console.log);
// 1 après 1 seconde, 2 après 2 secondes, 3 après 3 secondes
OpérateurContrôle du délaiCas d'utilisation
delayTemps fixeDélai uniforme simple
delayWhenDynamique (par valeur)Délai conditionnel, attente d'événement externe

⚠️ Notes importantes ​

1. L'Observable de délai est généré à chaque fois ​

ts
// ❌ Mauvais exemple : Réutilisation de la même instance Observable
const delayObs$ = timer(1000);
source$.pipe(
  delayWhen(() => delayObs$)  // Ne fonctionne pas à partir de la 2e fois
).subscribe();

// ✅ Bon exemple : Génération d'un nouvel Observable à chaque fois
source$.pipe(
  delayWhen(() => timer(1000))
).subscribe();

2. Si l'Observable de délai ne se termine jamais ​

ts
import { of, NEVER } from 'rxjs';
import { delayWhen } from 'rxjs';

// ❌ Mauvais exemple : Retourner NEVER cause un délai éternel
of(1, 2, 3)
  .pipe(
    delayWhen(() => NEVER)  // Les valeurs ne sont jamais émises
  )
  .subscribe(console.log);
// Aucune sortie

L'Observable de délai doit émettre une valeur ou se terminer.

3. Gestion des erreurs ​

Si une erreur survient dans l'Observable de délai, le flux entier sera en erreur.

ts
import { of, throwError, timer, delayWhen } from 'rxjs';

of(1, 2, 3)
  .pipe(
    delayWhen(value => {
      if (value === 2) {
        return throwError(() => new Error('Erreur de délai'));
      }
      return timer(1000);
    })
  )
  .subscribe({
    next: console.log,
    error: err => console.error('Erreur :', err.message)
  });
// Sortie : 1
// Erreur : Erreur de délai

📚 Opérateurs associés ​

✅ Résumé ​

L'opérateur delayWhen contrôle dynamiquement le timing de délai de chaque valeur.

  • ✅ Possibilité d'appliquer différents délais par valeur
  • ✅ Contrôle de délai par événements externes ou Observables
  • ✅ Ajustement du timing de traitement selon la priorité ou le type
  • ⚠️ L'Observable de délai doit être généré à chaque fois
  • ⚠️ L'Observable de délai doit se terminer ou émettre une valeur
  • ⚠️ Attention à la gestion des erreurs

Publié sous licence CC-BY-4.0.