Node.js (ES6) - поток управления Promise с помощью Promise.all

Я пытаюсь создать очередь, которая обрабатывает параллельные HTTP-запросы.

Объект запроса создается для каждого HTTP-запроса, например.

{
    method: 'POST',
    uri: 'http://posttestserver.com/post.php',
    body: {
        some: 'foo'
    },
    json: true
}

Я передаю массив этих объектов и хочу добавить их в очередь, а затем выполнить фактический запрос.

ПРОБЛЕМА. Оператор Promise.all ожидает завершения всех запросов перед возвратом.

ВОПРОС: я хочу добавить все задачи в очередь и возвращаться после завершения каждого запроса, а не ждать их всех. Может кто посоветует, как отделить логику сделать запрос от добавления задач в очередь?

ПРИМЕЧАНИЕ: оба обещания-очереди и запрос-обещание возвращают обещания.

Вот что у меня есть:

"use strict";

const Queue = require("promise-queue");
const rp = require('request-promise');

const maxConcurrent = 10;
const maxQueue = Infinity;
const queue = new Queue(maxConcurrent, maxQueue);

var options = [
    {
        method: 'POST',
        uri: 'http://posttestserver.com/post.php',
        body: {
            some: 'foo'
        },
        json: true
    },{
        method: 'POST',
        uri: 'http://posttestserver.com/post.php',
        body: {
            some: 'bar'
        },
        json: true
    }
];

Promise.all(options.map(function(task) {
        return queue.add(function() {
            return rp(task);
        })
    }))
    .then(function(response) {
        log(response);
    })
    .catch(function(err) {
        log(err);
    });


function log(data) {
    console.log(JSON.stringify(data, undefined, 4));
}

person Ben    schedule 15.12.2015    source источник
comment
Попробуйте использовать Promise.race ([p1, p2], callback), чтобы получить результат из списка обещаний.   -  person MikeZhang    schedule 15.12.2015
comment
Моя ошибка, Promise.race получает результат только от первого "возлюбленного" обещания.   -  person MikeZhang    schedule 15.12.2015
comment
Я борюсь с возвратом после завершения каждого запроса.   -  person Roamer-1888    schedule 15.12.2015


Ответы (1)


Я бы рекомендовал вызвать цепочку обещаний внутри цикла forEach, например:

var queueTask = function(task) {
  // returns a promise
  return queue.add(function() { return rp(task); });
};

var logResponse = function(response) {
  console.log(response);
};

var catchErrors = function(err) {
  console.log(err);
};

options.forEach(opt => {
  queueTask()
    .then(logResponse)
    .catch(catchErrors);
})

ОБНОВЛЕНИЕ

В комментариях было упомянуто, что приведенный выше фрагмент не дает вам возможности узнать, когда последняя задача завершена. Это не было требованием исходного вопроса, но, поскольку в некоторых комментариях говорилось, что это может быть полезно, вот один из способов сделать это с помощью обещаний:

var runTasks = new Promise(function(resolve, reject) {

  var queueTask = function(task) {
    // returns a promise
    return queue.add(function() { return rp(task); });
  };

  var logResponse = function(response) {
    console.log(response);
  };

  var catchErrors = function(err) {
    console.log(err);
  };

  options.forEach((opt, i, arr) => {
    
    queueTask()
      .then(logResponse)
      .catch(catchErrors);
    
    if (i === arr.length-1) { resolve(); }
    
  });
  
});

var functionToRunWhenLastTaskCompletes = function() {
  console.log('All tasks are complete.');
};

// runTasks is a promise here, not a function
// so you don't need to call it like a function
runTasks
  .then(functionToRunWhenLastTaskCompletes)

person dwhieb    schedule 15.12.2015
comment
Спасибо @dwhieb - это идеально, действительно очень полезно! - person Ben; 15.12.2015
comment
@Ben - Обратите внимание, это не даст вам знать, когда будет выполнено последнее задание, если вы этого хотели. Вот для чего Promise.all() пригодится. - person jfriend00; 15.12.2015
comment
@ jfriend00 - это хороший момент. В данном случае это не требование, но спасибо за комментарий. Я пока не уверен, как я подойду к этому. Поразмышляю над этим;) - person Ben; 16.12.2015