Search code examples
javascriptrecursionpromisebluebird

Resolve recursive Promise after value is reached


I have a recursive method which essentially increments a value until it reaches a maximum.

increase(delay) {
    return new Promise((resolve, reject) => {
        if (this.activeLeds < this.MAX_LEDS) {
            this.activeLeds++
            console.log(this.activeLeds)
        }
        return resolve()
    }).delay(delay).then(() => {
        if (this.activeLeds < this.MAX_LEDS) {
            this.increase(delay)
        } else {
            return Promise.resolve()
        }
    })
}

I'm testing some functionality and I want to know when the increase() method has been completed (aka resolved).

bounce(delay) {
    return new Promise((resolve, reject) => {
        this.increase(50).then(console.log('done'))
    })
}

However, I think I'm doing something wrong when I'm resolving the promise after

this.activeLeds < this.MAX_LEDS

is no longer true. I think it has something to do with the fact that I'm not resolving the original promise but I can't figure out how to fix it.


Solution

  • You were forgetting to return the result of the recursive call from the then callback, so it couldn't be awaited and the promise would just fulfill immediately.

    Use

    increase(delay) {
        if (this.activeLeds < this.MAX_LEDS) {
            this.activeLeds++
            console.log(this.activeLeds)
        }
        return Promise.delay(delay).then(() => {
            if (this.activeLeds < this.MAX_LEDS) {
                return this.increase(delay)
    //          ^^^^^^
            }
        })
    }
    

    Btw, I would recommend to avoid testing the condition twice on every iteration, and also stop immediately without a delay even on the first call:

    increase(delay) {
        if (this.activeLeds < this.MAX_LEDS) {
            this.activeLeds++
            console.log(this.activeLeds)
            return Promise.delay(delay).then(() => // implicit return from concise arrow body
                this.increase(delay)
            )
        } else {
            return Promise.resolve()
        }
    }