Sergey Novikov
Sergey Novikov

Reputation: 4196

Chain promises while condition is true

I'm trying to get all pages requsted via XHR using JS Promise.

For me it's relatively trivial to get this with recursive callbacks, but how I can achieve this with promises?

Simplified example without promises:

class Foo {
    getPages(callback, pagesCount)
    {
        if (typeof(pagesCount) === 'undefined') {
            pagesCount = 0;
        }

        // Let's say its async XHR
        window.setTimeout(() => {
            ++pagesCount;
            // Let's say that in 90% of cases we will get a full page
            if (Math.random() < 0.9) {
                console.log('Page received!');
                this.getPages(callback, pagesCount);
            } else {
                console.log('Last page received!');
                callback(pagesCount);
            }
        }, 1000);
    }

    doStuff(pagesCount)
    {
        console.log('Total pages: ' + pagesCount);
    }

    run()
    {
        this.getPages(this.doStuff);
    }
}

(new Foo()).run();

And I'm trying to achieve something like:

class Foo {
    getPages()
    {
        ...
    }

    doStuff(pagesCount)
    {
        console.log('Total pages: ' + pagesCount);
    }

    run()
    {
        this.getPages().then(this.doStuff);
    }
}

(new Foo()).run();

Upvotes: 1

Views: 66

Answers (1)

slebetman
slebetman

Reputation: 113866

Before the advent of async/await recursive promises were indeed impossible. You'd have to convert the promise into a callback friendly code and do your recursion using callbacks.

However, async/await allows you to do what you want:

async getPages(pagesCount)
{
    if (typeof(pagesCount) === 'undefined') {
        pagesCount = 0;
    }

    // Let's say its async XHR
    while () {

        // Call promisified XHR like this:
        // xhrResult = await XHR();

        // Call callback based XHR like this: 
        // xhrResult = await new Promise(function(ok,err){
        //   XHR(function (error, result) {
        //     if (error) {
        //       err(error)
        //   } else {
        //       ok(result)
        //   }    
        // });

        if (Math.random() < 0.9) {
            console.log('Page received!');
            return await getPages(pagesCount);
        } else {
            console.log('Last page received!');
            return pagesCount;
        }
    };
}

Note: all functions marked async return promises. So now you can do:

getPages(100).then(count => console.log(count + ' pages left'))

Upvotes: 3

Related Questions