【问题标题】:Promise: skip all fulfill and reject reactions but execute .finally承诺:跳过所有完成和拒绝反应,但执行 .finally
【发布时间】:2019-09-12 23:13:11
【问题描述】:

我有一个名为request的函数:

function request (endpoint) {
  return axios.request(endpoint).then(api.onSuccess).catch(api.onError)
}

api.onSuccess:

  onSuccess (response) {
    let breakChain = false
    ... some logic goes here ...
    return breakChain ? (new Promise(() => {})) : response
  }

api.onError:

  onError (error) {
    let breakChain = false
    ... some logic goes here ...
    if (breakChain) {
      return new Promise(() => {})
    } else {
      throw error
    }
  }

api 包含许多函数,这些函数代表基于提供的端点数据的不同 API 调用并返回 request(endpoint)

目前我有代码,如您所见,它返回带有空执行程序的 Promise,该执行程序始终处于挂起状态,以阻止后续 .then(...).catch(...) 处理程序链的执行,因为它们只是无限地等待该 Promise解决。这样做是为了处理某些具有通用响应处理的 API 响应(例如代码 >= 500 的响应)。 问题是现在我需要调用.finally()(就像在 Vue 食谱中 - https://vuejs.org/v2/cookbook/using-axios-to-consume-apis.html#Dealing-with-Errors)来恢复某些组件的状态,不管是否有错误,但是这种挂起 Promise 的方法是一个障碍。

问题是:是否可以跳过此类处理程序之一中的所有后续.then(...).catch(...) 调用以直接转到.finally()

更新。我没有提到重要的一点 - api.onSuccessapi.onErrorbasic 处理程序。在另一个应用程序组件中,附加处理程序附加到request 函数中呈现的基本链的末尾。一些 API 调用的通常链具有以下结果形式:

return axios.request(endpoint).then(api.onSuccess).catch(api.onError).then((response) => {...}).catch(() => {...}).finally(() => {...})

(有时没有.finally().catch(...) 块)

【问题讨论】:

  • api.onSuccessapi.onError 的作用是什么?从这里看起来他们所做的只是让request的正确使用变得困难。
  • @TJCrowder 它们是初始处理程序 - 即 api.onError 检查响应是否具有代码 >= 500,如果是,则将 breakChain 标志设置为 true 作为这种情况(代码 >= 500 ) 在整个应用程序中具有通用处理
  • @RomanYakubovich 您可以随时编写自己的Promise-like 并实现所有花哨的东西。 (甚至不需要符合标准。)

标签: javascript vue.js promise


【解决方案1】:

是否可以在此类处理程序之一中跳过所有后续 .then(...).catch(...) 调用以直接转到 .finally()

No.

目前我只是通过无限等待来停止链条 - 但是这种待处理的 Promise 方法是一个障碍。

确实,不要那样做。您可以通过using rejections (exceptions) for flow control 跳过then 处理程序,但更合适的方法是通过嵌套要跳过的链部分inside an if statement 来处理此问题。

这样做是为了处理某些具有通用响应处理的 API 响应(例如代码 >= 500 的响应)

为此,您应该使用类似的东西

return axios.request(endpoint).then(response => {
    …
}).catch(error => {
    if (api.handleCommonError(error)) return; // returns false if it couldn't handle the error
    …
}).finally(() => {
    …
});

是的,您不能在 api.request 函数中隐藏这种错误处理。

【讨论】:

    【解决方案2】:

    您可以使用asyncawait。所有现代浏览器都支持它们,并且您的捆绑器可以使它们与旧浏览器兼容。

    例如:

    async function request (endpoint) {
      try {
        const response = await axios.request(endpoint);
        return api.onSuccess(response);
      } catch (err) {
        api.onError(err);
      } finally {
        // Always executed, even if no error was thrown
      }
    }
    

    你也可以更传统地这样做:

    function request (endpoint) {
      return axios.request(endpoint).then(api.onSuccess, api.onError).then(() => {
        // Code is always executed after error / success
      }
    }
    

    【讨论】:

    • 我想我明白你的意思,但我不能用这种方式。请查看问题更新(抱歉最初没有包含)
    • 不,async/await 在这里没有帮助。如果 awaited 承诺永远不会解决,finally 块仍然不会运行。
    • 如果等待的承诺没有解决任何问题,thencatch 都不会发生。使用 async / await 至少可以让您比使用 Promise 更轻松地分支并执行条件逻辑。
    猜你喜欢
    • 2013-07-21
    • 2018-02-18
    • 2017-07-16
    • 2016-10-20
    • 2021-03-03
    • 1970-01-01
    • 2015-11-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多