цикл запрос-обещание, как включить данные запроса, отправленные с ответом?

Я пытаюсь использовать запрос-обещание в цикле, а затем отправить ответ клиенту со всеми ответами. Приведенный ниже код работает, однако я хочу также включать данные запроса в каждый ответ, чтобы идентификатор запроса можно было сопоставить с результатом. Есть ли встроенный способ сделать это:

promiseLoop: function (req, res) {
    var ps = [];
    for (var i = 0; i < 3; i++) {
        // var read_match_details = {
        //     uri: 'https://postman-echo.com/get?foo1=bar1&foo2=bar2',
        //     json: true // Automatically parses the JSON string in the response 
        // };
        var session = this.sessionInit(req, res);
        if (this.isValidRequest(session)) {
            var assertion = session.assertions[i];
            const options = {
                method: 'POST',
                uri: mConfig.serviceURL,
                body: assertion,
                headers: {
                    'User-Agent': 'aggregator-service'
                },
                json: true
            }
            logger.trace(options);
            ps.push(httpClient(options));
        }

    }

    Promise.all(ps)
        .then((results) => {
            console.log(results); // Result of all resolve as an array
            res.status(200);
            res.send(results);
            res.end();
        }).catch(err => console.log(err));  // First rejected promise
}

person Community    schedule 13.04.2020    source источник


Ответы (1)


Предполагая, что httpClient() — это request-promise, на которое вы ссылаетесь, а значение assertion — это то, что вы пытаетесь передать с этим результатом, вы можете изменить это:

ps.push(httpClient(options));

к этому:

ps.push(httpClient(options).then(result => {
    return {id: assertion, result};
}));

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


Ваш код не показывает текущий результат. Если это уже объект, вы также можете просто добавить свойство id к этому объекту, если хотите. Это зависит от вас, как именно вы объедините этот окончательный результат.

ps.push(httpClient(options).then(result => {
    // add id into final result
    result.id = assertion;
    return result;
}));

В любом случае, общая идея заключается в том, что перед тем, как поместить промис в массив, вы используете обработчик .then(), чтобы немного изменить возвращаемый результат, добавляя любые данные, которые вы хотите добавить, а затем возвращая этот новый измененный результат, чтобы он стал разрешенным значением цепочка обещаний.


Чтобы убедиться, что вы обрабатываете все ответы, даже если в некоторых из них есть ошибка, вы можете использовать более новый [Promise.allSettled()][1] вместо Promise.all(), а затем просмотреть, какие ответы были успешными или неудачными при обработке результатов. Или вы можете отлавливать любые ошибки, превращать их в разрешенные промисы, но присваивать им смысловое значение (часто null), которое вы можете увидеть при обработке окончательных результатов:

ps.push(httpClient(options).then(result => {
    // add id into final result
    result.id = assertion;
    return result;
}).catch(err => {
    console.log(err);
    // got an error, but don't want Promise.all() to stop
    // so turn the rejected promise into a resolved promise
    // that resolves to an object with an error in it
    // Processing code can look for an `.err` property.
    return {err: err};
}));

Затем, позже в вашем коде обработки:

Promise.all(ps)
    .then((results) => {
        console.log(results); // Result of all resolve as an array

        // filter out error responses
        let successResults = results.filter(item => !item.err);
        res.send(successResults );
    }).catch(err => console.log(err));  // First rejected promise
person jfriend00    schedule 13.04.2020
comment
Спасибо, что сработало! Однако у меня все еще осталась несвязанная проблема, я ожидаю несколько ответов, отличных от 200, (403), и в этом случае я все еще хочу, чтобы Promise.all(ps) прошел все результаты. Однако я обнаружил, что любой код состояния 400 вызовет блокировку catch. Есть ли способ обойти это? - person ; 13.04.2020
comment
@ Ramen223 - Посмотрите, что я добавил к своему ответу. - person jfriend00; 13.04.2020
comment
@ Ramen223 - Также обратите внимание, что вам не нужен res.status(200), так как это уже статус по умолчанию. И вы не звоните res.end() после res.send(). res.send() автоматически завершает HTTP-ответ. - person jfriend00; 13.04.2020
comment
Благодарю вас! Я смог заставить все работать как надо с этой информацией, очень ценю помощь. - person ; 14.04.2020