用Promise执行数组中的Promise.all破坏了它们

时间:2018-06-20 14:30:48

标签: javascript ecmascript-6 promise

我在getOrdersByUserId()中使用了一组userId,以获取这些用户在特定月份下的订单:

function getOrdersByUserId(userId, month = 4) {
    const apiService = new ApiService();

    return apiService.getOrdersList(`?OrderingUser=${userId}`)
        .then(orders => {
            const monthOrders = orders.filter(order => new Date(order.FromTime)
            .getMonth() === month);

            return monthOrders;
        });
}

这是ApiService中的getOrdersList():

getOrdersList(queryString = '') {
    return httpsRequest.createRequest(this.URL.ordersList + queryString, {}, this.requestHeaders, 'GET')
        .then(result => JSON.parse(result).Records);
}

httpsRequest.createRequest返回一个承诺,该承诺可以通过API的响应来解决(如果需要,我也可以共享该代码)。

当我使用我拥有的8个用户ID测试getOrdersByUserId()时,每次都会得到正确的记录。当我将这些调用放入promise链中并使用Promise.All()执行它们时,就会中断。我在此答案的帮助下编写了以下代码:Wait for forEach with a promise inside to finish

const promises = userIds.map(userId => {
            return getOrdersByUserId(userId, month)
                .then(orders => {
                    return orders;
                });
        });

        Promise.all(promises).then(results => {
            console.log(results);
        }).catch(err => {
           console.log(err);
        });

使用8个userId进行测试时,出现四到五次此错误:

(node:1) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): SyntaxError: Unexpected end of JSON input

大量控制台记录后,当httpsRequest.createRequest()给出的结果为空字符串而不是来自API的JSON响应时,似乎会发生此错误。那么,为什么所有这些具有相同userId的调用都可以单独工作,但是在promise链中执行时却中断了呢?我该如何解决?

1 个答案:

答案 0 :(得分:2)

您有一个常见的误解:您不执行承诺Promise.all不会“运行”任何内容。许诺只是一种观察操作以了解何时完成以及它是否起作用的方法。

在您的情况下,操作一经调用apiService.getOrdersList就开始。

您所看到的暗示

  1. API服务不喜欢您同时发送八个请求(也许是速率限制),并且

  2. API服务的承诺将使用无效的JSON值进行解析,而不是在无法处理#1时拒绝(这很不幸,它应该拒绝而不是解析)。

使用Promise.all不会破坏这些操作。但显然,并行运行这些操作中的八个。

您可以连续运行它们(一个接一个):

userIds.reduce((p, userId, index) => {
    return p.then(results => {
        return getOrdersByUserId(userId, month)
         .then(orders => {
             results[index] = orders;
             return results;
         });
    });
}, Promise.resolve([]))
.then(results => {
    // `results` is an array of results, in the same order as `userIds`
})
.catch(err => {
   console.log(err);
});

每次对getOrdersByUserId的呼叫都等待上一个呼叫完成;最终结果是结果数组,其顺序与userIds数组相同。