【问题标题】:Nested promises in NodeJSNodeJS 中的嵌套承诺
【发布时间】:2021-03-11 18:20:56
【问题描述】:

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

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

如果不是前两种情况之一,我将解决承诺并传递到下一项。

问题在于第二种情况,因为在解决(当前项目的)主要承诺之前,我必须等待调用仓库中的零件计数器结束。由于是异步代码,当当前进入第二个“else”时,会触发对库存计件器的调用,并立即解析promise,无需等待调用结束。 我该如何解决这种串联的承诺?

这是代码:

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);

【问题讨论】:

  • 我认为您应该将代码重构为几个函数。所以它会更容易阅读和维护。
  • 循环中似乎有很多地方可以解决看似单一的 Promise ...
  • 您能否提供您正在使用的数据的结构。它会更容易推理,并编写一些测试代码

标签: javascript node.js promise es6-promise


【解决方案1】:

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

如果产品存在,您需要进行子查询这一事实不是问题; then(和catch)总是返回promise,所以如果你从你的回调中返回一个简单的值,他们创建的promise就会用那个值实现,但是如果你返回一个promise,他们创建的promiseresolved到那个承诺(他们等待另一个承诺解决并以同样的方式解决)。

以下是根据问题中的代码您可能如何做到这一点的草图:

// 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 fulfilling 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`
                                  // fulfills with back into just the `currentItem`
    });
}));

【讨论】:

  • @panagulis72:上面的代码不会导致该错误,您必须引入了导致该错误的更改。 currentItem 在顶部明确定义,所有其余代码都嵌套在该范围内。但无论如何,它只是作为一个指南,而不是“这是代码,不客气”。阅读 cmets,了解它在做什么,并根据需要进行调整。
猜你喜欢
  • 1970-01-01
  • 2019-10-28
  • 2017-02-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-22
相关资源
最近更新 更多