简体   繁体   English

复杂承诺返回链中的Promise catch()顺序

[英]Promise catch() order in complex promise return chain

How is the error caught, when I return a promise from function A to function B, return the data from A's then, and both calls catch on the Promise? 当我从函数A向函数B返回承诺,然后从A的返回数据,并且两个调用都在Promise上捕获时,如何捕获错误? I know, when promise is resolved, A's then always gets executed first, followed by B's then with the data returned from A's then. 我知道,当诺言得到解决时,A总是总是首先执行,然后是B,然后是A所返回的数据。 But I can't wrap my head around how errors are caught, when this kind of returning of Promises forms a long chain. 但是,当这种承诺的回报形成一条长链时,我无法全神贯注于如何捕获错误。 Here is the simplified sample of the scenario. 这是该方案的简化示例。 I'm using Redux-thunk action creators to manage the state. 我正在使用Redux-thunk动作创建者来管理状态。

function postActionCreator(data) {
  return (dispatch) => {
    dispatch(type: POST_LOADING)
    return Source.post()
      .then(response => {
        dispatch(type: POST_SUCCESS, payload: response)
        return response
      })
      .catch(error => {
        // Is this catch called if handlePost throws error in then?
        dispatch(type: POST_ERROR, payload: error)
        throw new Error(error)
      })
  }
}

// Container component's post function calling the Redux action creator
function handlePost(data) {
  this.props.postActionCreator(data)
    .then(response => {
      // Do something with response
    })
    .catch(error => {
      // Or is the error caught with this catch?
    })
}

// Or are the both catchs called, in which order and why?

How is the error handled in these three different scenarios: 在以下三种不同情况下如何处理错误:

  • Source.post throws and error Source.post抛出和错误
  • postActionCreator's then throws an error 然后,postActionCreator引发错误
  • handlePost's then throws an error 然后handlePost引发错误

When using promises, a function should do one of three things: 使用promise时,函数应执行以下三项操作之一:

  1. Return a value 返回值
  2. Return a promise 兑现承诺
  3. Throw an error 引发错误

For this question, we're not too concerned with the first two cases, but you can read about the promises resolution procedure here for more information. 对于这个问题,我们不太关心前两种情况,但是您可以在此处阅读有关诺言解决程序的更多信息。 So let's take a look at that error case. 因此,让我们看一下该错误情况。

In JavaScript, errors - like most things - are just objects. 在JavaScript中,错误-就像大多数事物一样-只是对象。 Creating an error and choosing how to propagate that error are two different things. 创建错误和选择如何传播错误是两件事。 The two broad categories of propagating errors are synchronously and asynchronously. 传播错误的两大类是同步和异步的。 To propagate an error synchronously, you must throw it, for async, you just pass your error object through some predefined convention (such as a callback or promise). 要同步传播错误,必须throw错误;对于异步,只需通过一些预定义的约定(例如回调或promise)传递错误对象。

To answer the question fully, we need to understand how to handle these two different error types. 要完全回答该问题,我们需要了解如何处理这两种不同的错误类型。 For synchronous errors (that have been thrown), the only way to handle them (aside from a catch all event handler like window.onerror ) is to wrap them in a try/catch statement. 对于同步错误(已引发),处理它们的唯一方法(除了捕获所有事件处理程序,例如window.onerror )是将它们包装在try/catch语句中。 For async errors, we just follow the conventions of how to pass this data back up the call stack. 对于异步错误,我们仅遵循如何将这些数据传递回调用堆栈的约定。

So to answer your question with that knowledge: 因此,以这种知识来回答您的问题:

Source.post throws an error Source.post引发错误

If I assume by "throws an error" you mean that "an error occurred", we can't know how this will behave without knowing the source code of Source.post . 如果我假设“引发错误”是指“发生错误”,那么在不知道Source.post的源代码的情况下,我们将无法知道它的行为。 If an error was actually thrown, let's say there's some unexpected ReferenceError , then it won't actually be handled at all: 如果实际上抛出了一个错误,可以说存在一些意外的ReferenceError ,那么它实际上将不会被处理:

function post() {
  foo.bar; // will throw
}

function run() {
  post()
    .then(log)
    .catch(log);
}

Would result in: 将导致:

ReferenceError: foo is not defined
    at post (sync.js:6:3)
    at run (sync.js:10:3)
    at Object.<anonymous> (sync.js:15:1)

Now if the post function actually handled an error asynchronously, in this case by confirming to the promise conventions for passing errors, we'd see that it would get caught: 现在,如果post函数实际上异步处理错误,在这种情况下,通过确认传递错误的promise约定,我们将发现它会被捕获:

function post() {
  return new Promise((resolve, reject) => {
    reject('foo');
  });
}

function run() {
  post()
    .then(() => {})
    .catch((err) => {
      console.error('Caught error:', err);
    });
}

Results in 结果是

Caught error: foo

One more interesting part to this is that your code, in the catch statement actually throws a new Error object. 有趣的是,您的代码在catch语句中实际上抛出了一个新的Error对象。 In this case, we have one final thing to understand. 在这种情况下,我们还有最后一件事要理解。 We know that throwing an error synchronously means that it must be caught, but throwing an error from within a then function results in a rejected exception, not an error, so what's going on? 我们知道,同步引发错误意味着必须将其捕获,但是从then函数内部引发错误会导致拒绝的异常(不是错误),所以怎么回事? Well, the promise implementation is internally wrapping the function you pass to then in a try/catch block, then handling this error by rejecting the promise. 那么,承诺实现内部包裹你传递给函数then在一个try/catch块,然后通过拒绝承诺处理这个错误。 We can demonstrate this like so: 我们可以这样演示:

function post() {
  return new Promise((resolve, reject) => {
    resolve('foo');
  });
}

function run() {
  post()
    .then((result) => {
      throw result;
    })
    .catch((err) => {
      console.error('Caught error:', err);
    });
}

In this case, the error is also caught. 在这种情况下,错误也会被捕获。

postActionCreator's then throws an error 然后,postActionCreator引发错误

This now becomes simple. 现在,这变得很简单。 An error in a then is caught and propagated. then捕获并传播a中的错误。 It reaches the catch within postActionCreator then is rethrown to the outside catch . 它到达postActionCreatorcatch ,然后重新postActionCreator到外部catch

handlePost's then throws an error 然后handlePost引发错误

The simplest case. 最简单的情况。 It'll be caught internally and you'll get the error in the catch statement immediately after the then . 它会在内部被捕获, then会在catch语句中立即显示错误。


And finally, you may be thinking, "how can I handle those synchronous errors in Source.post ? What if that's not my function?". 最后,您可能会想,“如何处理Source.post那些同步错误?如果那不是我的功能呢?”。 Good question! 好问题! You can use a utility like promise.try from Bluebird to wrap this function for you. 您可以使用Bluebird的promise.try之类的实用程序为您包装此功能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM