Angular + RxJS : delayWhen
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
RxJSdelayWhen
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)
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));
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
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)); } }
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));