Search code examples
javascripttypescriptrxjsreactive-programming

Repeat with a variant delay


I currently have this piece of code:

import { Observable, defer, repeat } from 'rxjs'

const randNum = () => Math.floor(Math.random() * 10) + 1

const myObs = () => {
  return defer(() => {
    let delay = randNum()
    console.log('It will be delayed by', delay, ' secounds')
    delay = delay * 1000 // convert to ms
    return new Observable((subscriber) => {
      subscriber.next('hey there')
      subscriber.complete()
    }).pipe(repeat({ delay }))
  })
}

myObs().subscribe((val) => {
  console.log('this is the val', val)
})

which will output:

It will be delayed by {insert random number from 1 to 10} secounds
this is the val hey there
this is the val hey there
this is the val hey there
.
.
.

This will go on indefinitely which is what is desired however, I want the code inside the scope of the defer function to be run every time we repeat. So what I want would output something like this:

It will be delayed by {insert random number from 1 to 10} secounds
this is the val hey there
It will be delayed by {insert random number from 1 to 10} secounds
this is the val hey there
It will be delayed by {insert random number from 1 to 10} secounds
this is the val hey there
.
.
.

So that each time I get a new random number. and I am stuck trying to achieve that with rxjs or even without it.

Note: The code I am sharing is a simplified representation of the problem I have so please don't discuss the example per se but the problem it provides. questions like why do you want a random number each time? are an example of discussing the code instead of the problem.


Solution

  • In your case like this

    • inside defer use delay delay time
    • outside defer just repeat
    const randNum = () => Math.floor(Math.random() * 10) + 1
    
    const myObs = () => {
      return defer(() => {
        let delayNum = randNum()
        console.log('It will be delayed by', delayNum, ' secounds')
        delayNum = delayNum * 1000 // convert to ms
        return new Observable((subscriber) => {
          subscriber.next('hey there')
          subscriber.complete()
        }).pipe(delay(delayNum))
      }).pipe(repeat())
    }
    
    myObs().subscribe((val) => {
      console.log('this is the val', val)
    })
    

    or use delayWhen then repeat ?

    const randNum = () => Math.floor(Math.random() * 10) + 1
    
    const source$ = new Observable((subscriber) => {
      subscriber.next('hey there')
      subscriber.complete()
    });
    
    const delayTime = () => {
      let delay = randNum()
      console.log('It will be delayed by', delay, ' secounds')
      delay = delay * 1000 // convert to ms
      return timer(delay);
    }
    
    source$.pipe(delayWhen(delayTime), repeat()).subscribe((val) => {
      console.log('this is the val', val)
    })
    

    you can also do this, just repeat, but first time won't delay.

    source$.pipe(repeat({ delay: delayTime })).subscribe((val) => {
       console.log('this is the val', val)
    })