Angular + RxJS : delayWhen

By Arvind Rai, February 06, 2024
On this page we will learn to use RxJS delayWhen operator in our Angular application. RxJS delayWhen assigns a delay time for every values of source observable using an another observable. On subscribe of source observable, values will be emitted only after delay time has passed assigned to that value. delayWhen can be used to delay observable response on subscribe in HTTP operation or in other operation. delayWhen is also useful in Angular testing to delay response.
Here we will discuss delayWhen operator in detail with examples.

1. RxJS delayWhen

RxJS delayWhen operator delays the emission of source observable for a delay duration. The delay duration is obtained by the emission of another observable.
Find the delayWhen operator construct.
delayWhen(delayDurationSelector, subscriptionDelay) 
Parameters:
delayDurationSelector : A function that returns an observable to emit delay duration. For every value emitted by source observable delayDurationSelector returns a new observable that emits a time duration.
subscriptionDelay : Optional. It triggers the subscription to the source observable. Default is undefined.

Returns:
delayWhen returns an Observable that emits values after a delay emitted by another observable.

1. For every value of source observable, delayDurationSelector returns an observable that emits the time duration used to delay the start of emission by source observable. Once the time duration is over, source observable emits and delayDurationSelector returns another observable to emit next delay duration for source observable.
2. delayDurationSelector function has two arguments as (value: T, index: number), first argument is value emitted by source observable and second argument is emission order index of value from source observable.

2. Using delayWhen

Example-1 : Find a simple example.
of("A", "B", "C").pipe(
   delayWhen((v, i) => {
      console.log(v+"-"+i);
      return interval((i +1) * 3000);
   })
).subscribe(e => console.log(e)); 
The first argument of delayWhen is delayDurationSelector function that accepts two arguments, value and index. Here index is index of emitting order of values from source observable. Using value and index, we can create an observable that will emit delay time for this value to emit when source observable is subscribed. In above example, I am using index to generate different delay time for each emitting value from source.
The first emitting value is “A” with index 0, hence delay time for this value is (0+1) * 3000 = 3000 ms.
The second emitting value is “B” with index 1, hence delay time for this value is (1+1) * 3000 = 6000 ms.
The third emitting value is “C” with index 2, hence delay time for this value is (2+1) * 3000 = 6000 ms.
Delay Time count down for all the three values starts once source observable is subscribed. They will emit in following order.
Value ”A” will emit after 3 seconds once source observable is subscribed.
Value ”B” will emit after 3 seconds since the time “A” has emitted or we can say that “B” will emit after 6 seconds once source observable is subscribed.
Value ”C” will emit after 3 seconds since the time “B” has emitted or we can say that “C” will emit after 9 seconds once source observable is subscribed.

Output
A-0
B-1
C-2

(After 3 seconds)
A 
(After 6 seconds)
B
(After 9 seconds)
C 

Example-2 : Here duration time is decided by random function.
of("101", "102", "103").pipe(
   delayWhen(() => {
      return timer(Math.random() * 3000);
   })
).subscribe(e => console.log(e)); 
timer(Math.random() * 3000) creates observable that emits a random number. Hence the values of source observable will be assigned with random waiting time. For multiple run, output may vary.
Find the output in my case.
103
101
102 
Example-3 : Find the delayed click example.
import { AfterViewInit, Component, ElementRef, ViewChild } from '@angular/core';
import { delayWhen, fromEvent, timer } from 'rxjs';

@Component({
   selector: 'my-app',
   standalone: true,
   template: '<button #click>Click Me!</button>'
})
export class MyComponent implements AfterViewInit {
   @ViewChild('click') clickMe!: ElementRef;
   ngAfterViewInit() {
      const clicks$ = fromEvent(this.clickMe.nativeElement, 'click');
      clicks$.pipe(
         delayWhen((v, i) => {
            console.log(v + "-" + i);
            return timer(Math.random() * 5000);
         })
      ).subscribe(x => console.log(x));
   }
} 
RxJS fromEvent creates an observable that emits specified event from the given target. In the above code, click response is being delayed using delayWhen with random number in milliseconds.

3. delayWhen vs delay

1. delayWhen is like RxJS delay but difference is the way time duration is provided.
2. In delay operator, time duration is provided as number or Date whereas in delayWhen time duration is emitted by another observable.
3. We can say that delay operator assigns the same delay time to every emitted value from source observable but delayWhen can assign different delay time to each emitted value from source observable.
4. In delayWhen, we get emitted value and its index in source observable. These data can be used to decide delay time for that value.
//Using delay
from(["V1", "V2"]).pipe(
   delay(2000)
).subscribe(v => console.log(v));

// Using delayWhen
from(["V1", "V2"]).pipe(
   delayWhen(() => timer(2000))
).subscribe(v => console.log(v)); 

4. Reference

POSTED BY
ARVIND RAI
ARVIND RAI







©2024 concretepage.com | Privacy Policy | Contact Us