Javscript承诺:拒绝处理程序vs捕获

时间:2018-10-04 22:47:59

标签: javascript node.js promise

我遇到了多个应用程序,在这些应用程序中,使用catch优于rejectHandler。 例如: 首选

class TaskList extends Component {
    constructor(props) {
        super(props);
        this.state = {
            tasks: [
                {/* task 1 */},
                {/* task 2 */}
            ]
        }
    }
    appendTask = task => {
        let tasks = [...this.state.tasks];
        tasks.push(task);
        this.setState({tasks});
    }
    render() {
        const { tasks } = this.state;
        return (
            <div className="tasks">
                <ul>
                    {tasks.map(task => <TaskItem task={task}/>)}
                </ul>
                <NewTask appendTask={this.appendTask}/>
            </div>
        );
    }
}

class NewTask extends Component {
    /* ... */
    postDataHandler = () => {
        /* ... */
        .then(response => response.json())
        .then(response => {
            // append to existing list of tasks
            this.props.appendTask(response);
        })
        .catch(error => console.error('Error:', error));
    }
    /* ... */
}

代替

new Promise.then(resolveHandler).catch()

是否有特定原因?

我找到

new Promise().then(resolveHandler, rejectHandler).catch()

更有用,因为

  1. 我可以使用rejectHandler解决调用Promise.reject的设计/预期错误情况。
  2. 我可以使用catch块来解决未知的/意外的编程/运行时错误。

有人知道不经常使用rejectHandler的任何特定原因吗?

P.S。我知道ES6中有较新的替代方法,但我只是好奇地知道这一点。

更新:我知道如何拒绝处理程序并捕获工作。问题是为什么我看到更多的人只使用catchHandler而不是catchHandler和catch?这是最佳做法还是有优势?

更新(在此处添加答案):找到了我要找的第一手答案。 原因不仅仅在于拒绝中的错误是由catch处理的,还主要是由于链接。当我们将promise.then.then.then.then链接起来时,拥有一个解决方案,拒绝模式被证明很难将其链接起来,因为您不想实现一个拒绝处理程序,而只是将rejectData向前转发。事实证明,仅使用promise / then / catch以及resolve / return / throw可以非常有效地链接N个罐头。 @ Bob-Fanger(可接受的答案)也解决了部分问题。 例如:

new Promise().then(resolveHandler, rejectHandler).catch()

仅使用这些内容我只需要担心的是诺言/然后/追赶以及解决/返回/扔在链中任何地方。

3 个答案:

答案 0 :(得分:4)

区别在于,如果resolveHandler内部发生错误,则该错误不会由rejectHandler处理,那只能处理原始诺言中的拒绝。

rejectHandler不能与catch结合使用那么多,因为大多数时候我们只关心某事出了错。
仅创建一个错误处理程序可使代码更易于推理。

如果链中的特定承诺应以不同的方式处理,这可能是使用拒绝处理程序的原因,但是在这种情况下,我可能会写一个catch().then().catch()

答案 1 :(得分:1)

两个都不比另一个有用。当引发错误或拒绝承诺时,将同时拒绝被拒绝的处理程序和catch回调。

没有“最佳实践”来使用另一种。您可能会看到代码使用一种或另一种,但是其使用将基于代码需要实现的目的。程序员可能希望在链中的不同时间捕获错误,并以不同的方式处理在不同时间抛出的错误。

希望以下内容有助于解释我的意思:

somePromise
  .then(
      function() { /* code when somePromise has resolved */ },
      function() { /* code when somePromise has thrown or has been rejected. An error thrown in the resolvedHandler will NOT be handled by this callback */ }
   );

somePromise
  .then(
      function() { /* code when somePromise has resolved */ }
   )
   .catch(
      function() { /* code when somePromise has thrown or has been rejected OR when whatever has occurred in the .then chained to somePromise has thrown or the promise returned from it has been rejected */ }
   );

请注意,在第一个代码段中,如果解析的处理程序抛出,则没有可以捕获该错误的拒绝处理程序(或catch回调)。在解析的回调中引发的错误将不会被指定为.then

的第二个参数的rejectedHandler捕获。

答案 2 :(得分:0)

如文章中所述,在对.then的同一调用中提供解决和拒绝处理程序,可以将对先前承诺的拒绝与成功处理程序中引发的错误分开或从成功处理程序中返回拒绝的承诺进行处理

由于拒绝处理程序返回而不会引发错误,将恢复承诺链的已完成通道,因此,如果先前的拒绝处理程序正常返回,则不会调用最终的catch处理程序。

问题然后转移到用例,开发成本和知识水平。

用例

理论上,then调用的两个参数形式可用于重试操作。但是,由于硬编码的承诺链是静态设置的,因此重试操作并不简单。一种更简单的重试方法可能是将async函数与try {catch}语句一起使用,该声明围绕await的promise可能需要按以下概念代码进行重试:

async function() {
    let retries = 3;
    let failureErr = null;
    while( retries--) {
       try {
          var result = await retryableOperationPromise() 
          return result;
       }
       catch( err) {
          failureErr = err;
       }
     }
     throw failureErr // no more retries
}

其他用例可能并不广泛。

开发或商业决策的成本。

如果告诉用户稍后重试是可以接受的,那么它可能比对承诺被拒绝的特定原因进行任何操作都要便宜。例如,如果我试图在午夜预订机票,而航空公司却提价,我通常会被告知“发生错误,请稍后再试”,因为我将无法遵守预订开始时给出的价格。

知识(

我怀疑应许用法可能经常是基于示例而不是对主题的深入了解。对于缺乏经验的开发人员,程序经理也可能希望保持代码库尽可能简单(可能是成本问题)。

如果用法有效,则“最佳实践”可能不会真正适用于做出有关如何使用承诺的决策。一些开发人员和管理人员原则上会避免某种形式的使用,但并不总是基于技术优点。