如何从Promise的catch/then区块返回? [英] How to return from a Promise's catch/then block?

查看:74
本文介绍了如何从Promise的catch/then区块返回?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

关于使用JavaScript Promise进行编程时如何使用"then"和"catch"的许多教程.但是,所有这些教程似乎都遗漏了一个重要点:从then/catch块返回以打破Promise链.让我们从一些同步代码开始来说明这个问题:

There are many tutorials on how to use "then" and "catch" while programming with JavaScript Promise. However, all these tutorials seem to miss an important point: returning from a then/catch block to break the Promise chain. Let's start with some synchronous code to illustrate this problem:

try {
  someFunction();
} catch (err) {
  if (!(err instanceof MyCustomError))
    return -1;
}
someOtherFunction();

本质上,我正在测试捕获的错误,如果不是该错误,我希望我会返回到调用方,否则程序将继续.但是,此逻辑不适用于Promise:

In essence, I am testing a caught error and if it's not the error I expect I will return to the caller otherwise the program continues. However, this logic will not work with Promise:

Promise.resolve(someFunction).then(function() {
  console.log('someFunction should throw error');
  return -2;
}).catch(function(err) {
   if (err instanceof MyCustomError) {
     return -1;
   }
}).then(someOtherFunction);

此逻辑用于我的某些单元测试,在这些单元测试中,我希望函数以某种方式失败.即使我将catch更改为then块,我仍然无法破坏一系列链接的Promises,因为then/catch块返回的任何内容都将成为沿链传播的Promise.

This logic is used for some of my unit tests where I want a function to fail in a certain way. Even if I change the catch to a then block I am still not able to break a series of chained Promises because whatever is returned from the then/catch block will become a Promise that propagates along the chain.

我想知道Promise是否能够实现这种逻辑;如果没有,为什么?对我来说很奇怪的是,Promise链永远不会被打破.谢谢!

I wonder if Promise is able to achieve this logic; if not, why? It's very strange to me that a Promise chain can never be broken. Thanks!

在2015年8月16日 根据到目前为止给出的答案,由then块返回的被拒绝的Promise将通过Promise链传播,并跳过所有随后的then块,直到被捕获(处理).可以很好地理解此行为,因为它只是模仿以下同步代码(方法1):

Edit on 08/16/2015: According to the answers given so far, a rejected Promise returned by the then block will propagate through the Promise chain and skip all subsequent then blocks until is is caught (handled). This behavior is well understood because it simply mimics the following synchronous code (approach 1):

try {
  Function1();
  Function2();
  Function3();
  Function4();
} catch (err) {
  // Assuming this err is thrown in Function1; Function2, Function3 and Function4 will not be executed
  console.log(err);
}

但是,我要问的是同步代码中的以下情形(方法2):

However, what I was asking is the following scenario in synchronous code (approach 2):

try {
  Function1();
} catch(err) {
  console.log(err); // Function1's error
  return -1; // return immediately
}
try {
  Function2();
} catch(err) {
  console.log(err);
}
try {
  Function3();
} catch(err) {
  console.log(err);
}
try {
  Function4();
} catch(err) {
  console.log(err);
} 

我想以不同方式处理在不同功能中引发的错误.如方法1所示,有可能在一个catch块中捕获了所有错误.但是,这样一来,我必须在catch块内制作一个大的switch语句来区分不同的错误;此外,如果不同函数抛出的错误没有通用的可切换属性,那么我将完全无法使用switch语句;在这种情况下,我必须为每个函数调用使用单独的try/catch块.有时方法2是唯一的选择. Promise的then/catch语句不支持这种方法吗?

I would like to deal with errors raised in different functions differently. It's possible that I catch all the errors in one catch block as illustrated in approach 1. But that way I have to make a big switch statement inside the catch block to differentiate different errors; moreover, if the errors thrown by different functions do not have a common switchable attribute I won't be able to use the switch statement at all; under such a situation, I have to use a separate try/catch block for each function call. Approach 2 sometimes is the only option. Does Promise not support this approach with its then/catch statement?

推荐答案

使用该语言的功能无法实现.但是,可以使用基于模式的解决方案.

This can't be achieved with features of the language. However, pattern-based solutions are available.

这是两个解决方案.

抛出上一个错误

这种模式基本上是声音...

This pattern is basically sound ...

Promise.resolve()
.then(Function1).catch(errorHandler1)
.then(Function2).catch(errorHandler2)
.then(Function3).catch(errorHandler3)
.then(Function4).catch(errorHandler4)
.catch(finalErrorHandler);

Promise.resolve()不是严格必需的,但是允许所有.then().catch()行具有相同的模式,并且整个表达在眼睛上更容易.

Promise.resolve() is not strictly necessary but allows all the .then().catch() lines to be of the same pattern, and the whole expression is easier on the eye.

...但是:

  • 如果errorHandler返回结果,则链将前进到下一行的成功处理程序.
  • 如果抛出错误处理程序,则链将前进到下一行的错误处理程序.

除非编写错误处理程序以使它们能够区分先前引发的错误和新引发的错误,否则不会发生期望的跳出链条.例如:

The desired jump out of the chain won't happen unless the error handlers are written such that they can distinguish between a previously thrown error and a freshly thrown error. For example :

function errorHandler1(error) {
    if (error instanceof MyCustomError) { // <<<<<<< test for previously thrown error 
        throw error;
    } else {
        // do errorHandler1 stuff then
        // return a result or 
        // throw new MyCustomError() or 
        // throw new Error(), new RangeError() etc. or some other type of custom error.
    }
}

现在:

  • 如果errorHandler返回结果,则该链将前进到下一个FunctionN.
  • 如果errorHandler抛出MyCustomError,则它将被反复重新抛出链并被第一个不符合if(error instanceof MyCustomError)协议的错误处理程序捕获(例如,最终的.catch()).
  • 如果errorHandler引发任何其他类型的错误,则链将进行到下一个捕获.
  • if an errorHandler returns a result, then the chain will progress to the next FunctionN.
  • if an errorHandler throws a MyCustomError, then it will be repeatedly rethrown down the chain and caught by the first error handler that does not conform to the if(error instanceof MyCustomError) protocol (eg a final .catch()).
  • if an errorHandler throws any other type of error, then the chain will progress to the next catch.

如果您需要根据抛出的错误类型灵活地跳到链尾或不跳到链尾,此模式将很有用.我期望的情况很少.

This pattern would be useful if you need the flexibility to skip to end of chain or not, depending on the type of error thrown. Rare circumstances I expect.

演示

DEMO

绝缘扣

另一种解决方案是引入一种机制,使每个.catch(errorHandlerN)保持绝缘",以便仅捕获由对应的FunctionN引起的错误,而不是由先前的任何错误引起的错误.

Another solution is to introduce a mechanism to keep each .catch(errorHandlerN) "insulated" such that it will catch only errors arising from its corresponding FunctionN, not from any preceding errors.

这可以通过在主链中只有成功处理程序来实现,每个成功处理程序都包含一个包含子链的匿名函数.

This can be achieved by having in the main chain only success handlers, each comprising an anonymous function containing a subchain.

Promise.resolve()
.then(function() { return Function1().catch(errorHandler1); })
.then(function() { return Function2().catch(errorHandler2); })
.then(function() { return Function3().catch(errorHandler3); })
.then(function() { return Function4().catch(errorHandler4); })
.catch(finalErrorHandler);

在这里Promise.resolve()起着重要的作用.没有它,Function1().catch(errorHandler1)将会在主链中,而catch()不会与主链绝缘.

Here Promise.resolve() plays an important role. Without it, Function1().catch(errorHandler1) would be in the main chain the catch() would not be insulated from the main chain.

现在,

  • 如果errorHandler返回结果,则链将前进到下一行.
  • 如果errorHandler抛出任何喜欢的东西,那么该链将直接前进到finalErrorHandler.

如果您始终希望跳到链的末尾,而不考虑引发的错误类型,请使用此模式.不需要自定义错误构造函数,并且不需要以特殊方式编写错误处理程序.

Use this pattern if you want always to skip to the end of chain regardless of the type of error thrown. A custom error constructor is not required and the error handlers do not need to be written in a special way.

演示

DEMO

使用案例

选择哪种模式将取决于已经给出的考虑因素,也可能取决于项目团队的性质.

Which pattern to choose will determined by the considerations already given but also possibly by the nature of your project team.

  • 一个人的团队-您可以编写所有内容并理解问题-如果您可以自由选择,则可以根据自己的喜好运行.
  • 多人团队-由一个人编写主链,由其他人编写函数及其错误处理程序-如果可以,则选择Insulated Catatch-在主链控制下,您无需强制执行以某种方式编写错误处理程序的原则.

这篇关于如何从Promise的catch/then区块返回?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆