Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handle promise resolves indvidually in promise.all()

There is a lot of information on how to handle errors when using promise.all() using catch but what I'm trying to achieve is to handle every time a promise inside of this promise.all() resolves. The reason I'm trying to do this is because I am attempting to setup a custom progress bar in console and I need to call the tick method every time a promise is resolved.

this.getNewSources = function () {
    var bar = new ProgressBar(':bar', {total: this.getSourceMap().size});
    var timer = setInterval(function () {
        bar.tick();
        if (bar.complete) {
            console.log('\ncomplete\n');
            clearInterval(timer);
        }
    }, 100);

    let promiseArr = [];
    for (let x of this.getSourceMap().values()) {
        promiseArr.push(this.requestArticles(x.getName(), x.getCat(), x.getKey()));
    }

    return Promise.all(promiseArr).then(() => {
        console.log("Articles loaded this round: " + this.articles.size);
        console.log('all sources updated');
        this.loadedArticles = true;
        console.log(this.articleCount);
        console.log(this.articles.size);
    }).catch(e => {
        console.log(e);
    });
};

I'm trying to figure out a way of being able to call the bar.tick() method when each individual promise resolves.

like image 220
li x Avatar asked Oct 17 '22 13:10

li x


1 Answers

(Answering my own question.)

I handled it by adding a then handler where I'm getting the promise from requestArticles (where I'm pushing them into the promiseArr array). I had to be sure to pass the value that handler receives out of the handler so it propagates to Promise.all, see *** lines:

 this.getNewSources = function () {
    var bar = new ProgressBar(':bar', {total: this.getSourceMap().size});
    var timer = setInterval(function () {
        if (bar.complete) {
            console.log('\ncomplete\n');
            clearInterval(timer);
        }
    }, 100);

    function updateProgressBar() {
        bar.tick()
    }

    let promiseArr = [];
    for (let x of this.getSourceMap().values()) {
        promiseArr.push(this.requestArticles(x.getName(), x.getCat(), x.getKey())
            .then(value => {           // ***
                updateProgressBar();   // ***
                return value;          // ***
            })                         // ***
        );
    }

    return Promise.all(promiseArr).then(() => {
        console.log("Articles loaded this round: " + this.articles.size);
        console.log('all sources updated');
        this.loadedArticles = true;
        console.log(this.articleCount);
        console.log(this.articles.size);
    }).catch(e => {
        console.log(e);
    });
};

That way, my handlers get called as the promises complete individually, and since I'm returning the value I receive, the promise created by my call to then will resolve with that value, which Promise.all will see. Rejections will skip over that handler and go straight to the handlers hooked up by Promise.all.

The ascii progress library on npm

Result output in console:

console loading bar


(With thanks to T.J. Crowder for his initial explanation, which made me realize I could do this where I'm pushing onto the array. He said he preferred deleting that answer and having me post this instead.)

like image 80
li x Avatar answered Oct 31 '22 15:10

li x