4

I have a block of code that is responsible for taking an Observable<string[]>, then mapping that to Observable<string> and emitting the values 1 second apart from each other.

Think of this like a message ticker on a website.

My current code is working below:

    const arrayOfStrings$ = of([
        'Warming things up',
        'Getting things ready',
        'Welcome'
    ]);

    this.messages$ = arrayOfStrings$.pipe(
        switchMap((messages) => from(messages).pipe(
            concatMap((innerMessage) => of(innerMessage).pipe(delay(1000))),
        )),
        tap((message) => {
            console.log(`Message: ${message}`);
        })
    );

Is there a better way to do this with less code? It's mainly the switchMap() and concatMap() inside each other that is bothering me.

Thanks for any help and suggestions.

Edit: This is a simplified version of what I have running in my actual project. I am just trying to find an easier way to go from an Observable<string[]> to an Observable and delay each emission one second apart after each emission

Damian C
  • 2,111
  • 2
  • 15
  • 17

3 Answers3

7

You can use the concatMap() and delay() operators to make sure that each emission will be delivered one-by-one with a specified time interval.

const arrayOfStrings = [
  'Warming things up',
  'Getting things ready',
  'Welcome'
];

(from(arrayOfStrings)
  .pipe(
    concatMap(message => 
      of(message).pipe(delay(1_000))
    ),
  )
  .subscribe()
);
Slava Fomin II
  • 26,865
  • 29
  • 124
  • 202
martin
  • 93,354
  • 25
  • 191
  • 226
1
of('one', 'two', 'three')
  .pipe(zipWith(interval(1000)))
  .subscribe(console.log)

or if you want to start immediately replace interval with

timer(0, 1000)
Yuriy Naydenov
  • 1,875
  • 1
  • 13
  • 31
0

I would use the following code:

const arrayOfStrings$ = of([
  'Warming things up',
  'Getting things ready',
  'Welcome'
]);

arrayOfStrings$.pipe(
  mergeMap((a) => a),
  zip(timer(1000, 1000)),
  map(([a]) => a),
  tap(message => {
    console.log(`Message: ${message}`);
  })
);
Harald Gliebe
  • 7,236
  • 3
  • 33
  • 38
  • Thanks for taking a shot. fromArray() was deprecated in favor of from(), in the version of rxjs I'm using (v6). I cannot change the value of arrayOfStrings$, because in my project code this is connected to the output of a subject. Left that detail out because I wanted to simplify the problem. I'm starting with a Observable and I want to end with Observable spaced 1 second apart – Damian C Jul 01 '21 at 19:02
  • @DamianC I updated my code to use the original definition of `arrayOfStrings$`. The `mergeMap` with the identity function, _unpacks_ the strings of the subject. – Harald Gliebe Jul 01 '21 at 19:26