在节点请求的循环中等待所有完成的请求

Wating for all finished request in a loop with node request

我使用节点请求 ajax 包。所以,我有一个循环,在每次迭代中它都会向我的服务器发出请求。

// realItems needs the complete value of items assigned
var realItems;

var items = [];
_.forEach(JSON.parse(body), (value, key) => {
  request('myurl/' + id, (error, response, body) => {
    items = JSON.parse(body)
  });
});

我如何捆绑来自 request 包的所有请求,以便我可以将 items 变量的值分配给最后的 realItems

// 编辑:

我使用 React js,所以在这种情况下 realItems 是一个状态,我不能在每个循环迭代中触发它,因为渲染会在每个 setState

上触发

有多种方法可以解决这个问题。这是一个不保留结果顺序的蛮力方法:

var items = [];
var cnt = 0;
_.forEach(JSON.parse(body), (value, key) => {
  ++cnt;
  request('myurl/' + value.id, (error, response, body) => {
    items.push(JSON.parse(body));
    // if all requesets are done
    if (--cnt === 0) {
        // process items here as all results are done now
    }
  });
});

这是一个使用 Bluebird 承诺的版本:

var Promise = require('bluebird');
var request = Promise.promisify(require("request"));
Promise.promisifyAll(request);

var promises = [];
_.forEach(JSON.parse(body), (value, key) => {
    promises.push(request('myurl/' + value.id));
});
Promise.all(promises).then(function(results) {
    // all requests are done, data from all requests is in the results array
    // and are in the order that the requests were originally made
});

而且,这里有一个使用 Bluebird 迭代器的更简单的 Bluebird promises 方法:

var Promise = require('bluebird');
var request = Promise.promisify(require("request"));
Promise.promisifyAll(request);

Promise.map(JSON.parse(body), function(value) {
    return request('myurl/' + value.id);
}).then(function(results) {
    // all requests are done, data is in the results array
});

是否要求您使用 request 包?我使用类似的 async 并附带一个 parallel 方法,它完全符合您的要求 -

https://github.com/caolan/async#parallel

示例:

async.parallel([
  function(callback){
    setTimeout(function(){
        callback(null, 'one');
    }, 200);
  },
  function(callback){
    setTimeout(function(){
        callback(null, 'two');
    }, 100);
  }
],
// optional callback
function(err, results){
    // the results array will equal ['one','two'] even though
    // the second function had a shorter timeout.
});