Promise.map()进度指示器

时间:2017-07-08 14:40:19

标签: javascript arrays node.js concurrency promise

我正在尝试同时向JSON API发送许多GET请求。我在Node.js中使用Bluebird promises,并使用request-promise发送HTTP请求,如下所示:

const rp = require('request-promise');
//urlsArray is a 5000+ array of urls
Promise.map(urlsArray, url => {
  return rp(url)
    .then(results => { 
       return JSON.parse(results);
    }).catch(err => { log(error);});
}).then(resultsArray => {
  log(resultsArray); // print out results
}).catch(err => {
  log(error);
});

问题是,如果数组中有5000多个url,那么请求,即使是并发,也可能需要很长时间,因为map()会等到完成所有操作。当地图通过请求时,如何向控制台打印某种进度指示器(如百分比)?

我在每次请求后都尝试了log(results);,但这只是向控制台打印了5000个东西,这不是很方便。我更喜欢一个百分比,或一个显示大约完成了多少的数字。

1 个答案:

答案 0 :(得分:2)

请记住,承诺链只是:链条。因此,您可以为链中的每个承诺插入一个then来进行控制台更新,并让它只传回它收到的相同值。

实际上,查看代码时,您甚至不必这样做,因为您已经使用每个URL then处理程序来解析JSON。只需添加:

const rp = require('request-promise');
//urlsArray is a 5000+ array of urls
let completed = 0;                                 // ***
Promise.map(urlsArray, url => {
  return rp(url)
    .then(results => { 
       const parsed = JSON.parse(results);
       ++completed;                                // ***
       console.log(`Completed: ${completed}`);     // ***
       return parsed;
    }).catch(err => { log(error);});
}).then(resultsArray => {
  log(resultsArray); // print out results
}).catch(err => {
  log(error);
});

(注意我在说完该请求之前解析了JSON,以防JSON无效并抛出。)

但是,如果您尚未执行per-promise活动,则可以轻松插入then处理程序。这是一个这样做的例子(使用本机承诺,但它与Bluebird相同):

const data = [1, 2, 3, 4, 5];

function withoutReportingProgress() {
    return Promise.all(
        data.map(value => new Promise(resolve => {
            setTimeout(_ => {
                resolve(value);
            }, Math.random() * 500);
        }))
    );
}

function withReportingProgress() {
    let completed = 0;                              // ***
    return Promise.all(
        data.map(value => new Promise(resolve => {
            setTimeout(_ => {
                resolve(value);
            }, Math.random() * 500);
        })
        .then(value => {                            // ***
            ++completed;                            // ***
            console.log(`Completed: ${completed}`); // ***
            return value;                           // ***
        }))                                         // ***
    );
}

console.log("Starting without...");
withoutReportingProgress()
    .then(_ => {
        console.log("Done without");
        console.log("Starting with");
        withReportingProgress()
            .then(_ => {
                console.log("Done with");
            });
    });
.as-console-wrapper {
  max-height: 100% !important;
}