NodeJS中的嵌套承诺

时间:2017-12-01 08:19:49

标签: javascript node.js promise es6-promise

我正在NodeJS中编写一个服务,它检索一个Items列表。对于每一个,我必须创建一个指示可用项目数量的计数器。 因此,如果商品存在于商店中,则计数器只会递增并解析承诺(因为我确定最多只有一个库存)。

否则,如果它在库存中,我必须检查可用件的确切数量。

如果它不是前两个案例之一,我将解决这个承诺,然后转到下一个项目。

问题出在第二种情况,因为在解决主要承诺(当前项目)之前,我必须等待调用才能检索仓库中的零件计数器结束。由于它是一个异步代码,当它当前进入第二个“else”时,它会触发对股票中的计件器的调用,并立即解析承诺,而不等待调用结束。 我怎样才能解决这种承诺的连接?

这是代码:

let promises: any[] = [];
for (let i = 0, itemsLength = itemList.length; i < itemsLength; i++) {
let currentItem = itemList[i];
promises.push(
    new Promise(function(resolve: Function, reject: Function) {
        act({
            ...call the service to retrieve the item list
        })
        .then(function(senecaResponse: SenecaResponse < any > ) {
            if (senecaResponse && senecaResponse.error) {
                reject(new Error(senecaResponse.error));
            }
            currentItem.itemDetails = senecaResponse.response;

            currentItem.counters = {
                available: 0
            };

            if (currentItem.itemDetails && currentItem.itemDetails.length) {
                for (let k = 0, detailsLength = currentItem.itemDetails.length; k < detailsLength; k++) {
                    let currentItemDetail = currentItem.itemDetails[k];
                    if (currentItemDetail.val === "IN_THE_STORE") {
                        currentItem.counters.available++;

                        resolve();
                    } else if (currentItemDetail.courseType === "IN_STOCK") {
                        act({
                                ...call the service to retrieve the counter in stock
                            })
                            .then(function(stockResponse: SenecaResponse < any > ) {
                                if (stockResponse && stockResponse.error) {
                                    reject(new Error(stockResponse.error));
                                } else {
                                    currentItem.counters.available = stockResponse.response;
                                }
                                resolve();
                            })
                            .catch(function(error: Error) {
                                options.logger.error(error);
                                reject(error);
                            })
                    } else {
                        resolve();
                    }
                }
            } else {
                resolve();
            }
        })
        .catch(function(error: Error) {
            options.logger.error(error);
            reject(error);
        })
    })
);

}
   return Promise.all(promises);

1 个答案:

答案 0 :(得分:0)

请记住,您可以通过thencatch创建承诺的,其中每个处理程序一路转换分辨率值。由于您的act()显然会返回一个承诺,因此您的代码中根本不需要new Promise。相反,只需使用链。

如果产品存在,您需要进行子查询这一事实不是问题; then(和catch)总是返回promises,所以如果你从回调函数中返回一个简单的值,那么他们创建的promise将使用该值解析,但是如果你返回一个promise,那么他们创建的promise就是slaved对那个承诺。

以下是根据问题中的代码如何执行此操作的草图:

// Result is a promise for an array of populated items
return Promise.all(itemList.map(currentItem => {
    act(/*...query using `currentItem`...*/)
    .then(senecaResponse => {
        if (!senecaResponse || senecaResponse.error) {
            // Does this really happen? It should reject rather than resolving with something invalid.
            throw new Error((senecaResponse && senecaResponse.error) || "Invalid response");
        }
        currentItem.itemDetails = senecaResponse.response;
        currentItem.counters = {
            available: 0
        };
        return Promise.all((currentItem.itemDetails || []).map(currentItemDetail => {
            if (currentItemDetail.courseType === "IN_STOCK") {
                return act(/*...query using `currentItemDetail`...*/).then(stockResponse => {
                    currentItem.counters.available = stockResponse.response;
                });
            }
            if (currentItemDetail.val === "IN_THE_STORE") {
                currentItem.counters.available++;
            }
            // (We don't care what value we return, so the default `undefined` is fine; we
            // don't use the array from `Promise.all`
        }))
        .then(() => currentItem); // <== Note that this means we convert the array `Promise.all`
                                  // resolves with back into just the `currentItem`
    });
}));