【问题标题】:How to break out of promise-then chain in node js如何在节点js中打破promise-then链
【发布时间】:2019-01-09 21:35:23
【问题描述】:

我正在从事 SOA 项目,我正在编写一个节点 js 实用程序来完成我的工作。该实用程序首先使用 SOA 调用登录到服务器,然后调用一系列 SOA 调用,其中每个 SOA 调用取决于前一次调用的结果。

我使用promise-then 框架来实现这一点。以下是我的代码:

const loginPromise = postRequest(req, headersObj, loginUrl, Constants.loginData);
const queryPromise = loginPromise.then(loginSuccess, loginFailure);
const searchPromise = queryPromise.then(handleSavedQuerySearchResponse, onFailure);
const createPromise = searchPromise.then(handleSearchSoaResponse, onFailure);
const updatePromise = createPromise.then(handleCreateObjectSoaResposne, onFailure);
const plantDataPromise = updatePromise.then(handleUpdateObjectSoaResponse, onFailure);

function postRequest(request: any, header: any, reqUrl: string, jsonData: any): Promise<any> {
    return new Promise((resolve) => {
        request.post({
            headers: header,
            url: reqUrl,
            body: JSON.stringify(jsonData),
        }, (err: any, resp: any, bodyParam: any) => {
            resolve({error: err, response: resp, body: bodyParam});
        });
    });
}

成功执行一个 SOA 后,下一个 SOA 将从 callback 函数中执行。没有错误情况时一切正常。但是,如果服务器关闭或出现任何其他故障情况,我想摆脱这个promise-then 链。

当前,如果出现任何错误,流程将转到 onFailure 方法,但在执行后,它会将控制权交给链中的下一个承诺,并以 null 作为该方法的输入。

我想在遇到任何错误时退出 promise-then 链,并且不应执行其余的 promise。如果有人能帮我解决这个问题,我将不胜感激。

【问题讨论】:

  • 什么是“promise-then”框架?你是在谈论原生承诺吗?
  • 另外你使用的是什么请求框架?如今,许多请求框架都支持开箱即用的 Promise,因此您不必将 request.post 包装在新的 Promise 中。无论如何,这看起来像是一种非正统的链接承诺的方式。我将对其进行重构,以便您使用 async/await 以便或多或少地保留当前结构,但使用 try/catch 块来执行错误处理而不是 onFailure 回调,或者使用带有 .then 的常规 Promise 链接和.catch。如果你正常链接它们并在最后添加一个 .catch-block ,你应该得到你想要的行为
  • @Metareven 是的,我使用的是nodejs的原生promise,使用的是node包的请求库request@2.81.0
  • 如果您可以使用 async/await 对其进行重构并让我知道如何处理错误情况,这将非常有帮助。如果您可以在当前结构中添加 try/catch 块并帮助我实现所需的行为,那就太好了。
  • 您已经发现了问题:不要在 每个 步骤之后处理 onFailure 的错误 - 在链的末尾处理一次!

标签: javascript node.js promise request soa


【解决方案1】:

此代码尚未经过测试,因此应该更像是伪代码而不是实际解决方案:

尝试像这样重构您的代码:

const request = require('request-promise-native')

postRequest(req, headersObj, loginUrl, Constants.loginData)
    .then(loginSuccess)
    .then(handleSavedQuerySearchResponse)
    .then(handleSearchSoaResponse)
    .then(handleCreateObjectSoaResposne)
    .then(handleUpdateObjectSoaResponse)
    .catch(console.error)

function postRequest(request: any, header: any, reqUrl: string, jsonData: any): Promise<any> {
    return request.post({
        headers: header,
        url: reqUrl,
        body: JSON.stringify(jsonData),
    }, (err: any, resp: any, bodyParam: any) => {
            resolve({error: err, response: resp, body: bodyParam});
    });
}

错误处理是承诺链的一部分。

或者你可以用 async/await 做几乎相同的事情。

如果你想做一些实际的错误处理,你可以在这里添加你的 onFailure 函数,而不仅仅是 console.error

【讨论】:

  • "或者你可以用 async/await 做几乎相同的事情" 有点误导,因为语法是 very 不同的。您应该考虑更新您的答案以包含一个示例,考虑到如今 async / await 几乎总是一种更惯用的编写异步代码的方式。不过,话虽如此,这可能是一种链式 Promise 实际上更简洁的场景(假设每个 Promise 都依赖于前一个 Promise 的结果)。
  • 所以我从你的代码 sn-p 中了解到,任何发生在 promise 中的错误都会被捕获到 catch 块中,并且在 catch 块中我可以处理相应的错误。一旦错误被处理,下一个承诺将不会被调用。如有错误请指正。
  • @Akash_Kumar 是的,你假设正确。 Promise 可以与 then、catch、finally 方法链接。当一个 Promise 被拒绝时,它会在 Promise 链中冒泡,直到它被捕获或未被处理(这会给你一个警告,可能会在更高版本的节点中升级为异常)。如果您想在处理错误后继续链接,您所要做的就是在 .catch 之后附加一个 .then 并继续正常链接。我会看看我是否可以设法用 async/await 挤出一个更新的答案,但我现在没有时间这样做
  • @Metareven 感谢您的支持。我会试试这个,然后更新分析。
  • 按照原代码应该是.catch(onFailure)
猜你喜欢
  • 2016-03-27
  • 2018-09-20
  • 1970-01-01
  • 2020-10-22
  • 1970-01-01
  • 2017-12-03
  • 2017-12-07
  • 2016-06-17
  • 1970-01-01
相关资源
最近更新 更多