【问题标题】:Creating reusable promises without .catch在没有 .catch 的情况下创建可重用的 Promise
【发布时间】:2019-07-20 09:24:54
【问题描述】:

我正在一个新的代码库中工作,该代码库的模式是一些可重用函数从链中返回一个承诺,但它们不处理错误。

这是一个例子:

function createScheduleForGroup(group) {
  if (notInProduction()) {
    group.gschedScheduleId = '0';
    return Bluebird.resolve(group);
  }
// note: schedule is a global within the file
  return schedule.createSchedule(group.name).then(function (schedule) {
    group.gschedScheduleId = schedule.id;
    return group.save();
  });
}

在上面的示例中,没有 .catchreject 函数传递给 .then

该函数最终用于处理错误的快速路由中:

router.post('/schedule', function(req, res, next) {
       scheduleLogical
         .createScheduleGroup(req[config.entity])
         .then(function(group) {
           res.status(201).json(group);
         })
         .catch(next); 

// if creteScheduleGroup throws an error it is handled here

不为函数返回的 Promise 定义错误处理程序并预测使用该函数的人附加适当的错误处理程序是否是一种常见模式?

为了让我自己的理解更清楚,我对这个特定的函数和 Promise 链中使用的所有函数进行了模拟。这里是:

function getScheduleMock() {
  // this promise promisifys an older api that uses callbacks
  return new Promise((resolve, reject) => {
    // note this is simulating an api call:
    const response = Math.round(Math.random());
    // 0 === err, 1 === success

    if(response === 0) return reject(response);
    resolve(response);
    
  })
  // error hanlding :)
  .catch(err => {
    console.log(err);
    return Promise.reject(err);
    // there is an error handling function that logs the errors. If the error doesn't match expected errors, it rejects the error again as I have here.
  })
  .then(responseData => {
    return Promise.resolve(responseData);
  })
}

function createScheduleForGroupMock() {
  return getScheduleMock().then(responseData => Promise.resolve('everything worked :)'));
 // Note: group.save() from the original returns a promise
  // just like the actual example, the promise is returned
  // but there isn't any form of error handling except within the getScheduleMock function
}

createScheduleForGroupMock(); // when the error is rejected in the .catch() in getScheduleMock, the error is unhandled.

/* ***************** */


/* the createScheduleForGroup method is used within an express route which has error handling, here is an example of the code: */

// router.post('/schedule', function(req, res, next) {
//       scheduleLogical
//         .createScheduleGroup(req[config.entity])
//         .then(function(group) {
//           res.status(201).json(group);
//         })
//         .catch(next); 
        
// if creteScheduleGroup throws an error it is handled here

我对错误处理承诺相当陌生,从我一直在阅读和练习的内容来看,我通常认为您应该始终包含错误处理程序。我正在使用的代码库有很多使用createScheduleForGroup 模式的方法,其中没有在函数中定义错误处理程序,而是在使用函数后对其进行处理和附加。

createScheduleForGroup 中使用的一些函数会处理它们自己的错误,我对何时处理返回承诺的函数中的错误以及何时在使用该函数时附加它们的平衡感到困惑和好奇。

【问题讨论】:

  • Promise 错误处理与传统的错误处理没有什么不同,只有在可以优雅处理错误时才应该catch,在所有其他情况下,错误处理应该推迟到调用方法。
  • 我还要补充一点,catch-log-rethrow 是一种反模式。理想情况下,您应该将错误气泡一直到处理程序,该处理程序在关闭和重新启动应用程序之前记录错误,或者在处理错误时记录错误(如果需要)。

标签: javascript


【解决方案1】:

不为函数返回的 Promise 定义错误处理程序并期望使用该函数的人附加适当的错误处理程序是一种常见的模式吗?

是的,完全正确。这不仅仅是“一种常见的模式”,而是绝对的标准模式。

就像您不会在每个同步函数中放置 try/catch 语句一样,您不会在返回的每个 promise 上放置 .catch 回调。其实是considered an antipattern 来捕捉你无法处理的错误。

【讨论】:

    【解决方案2】:

    您可以在每个函数中都有一个错误处理程序。

    function aPromise() {
    
       return new Promise(function(resolver, reject){
    
          //Handle any error here and attach different information via your own errror class
    
       })
    
    }
    
    async function parentProcess() {
    
       try{
        await aPromise()
       }
       catch(e) {
           //Handle and attach more info here
       }
    }
    
    function grandParentProcess() {
    
       try{
         parentProcess();
       }
       catch(e){
           //Handle the error
       }
    
    }
    

    如果祖父函数处理错误以避免UnhandledPromiseRejection 错误,则您基本上不必处理父函数中的错误。

    【讨论】:

    • 谢谢!我认为我的主要问题是在处理更大的代码库时,在创建返回承诺的函数时是否有最佳实践?我知道如果祖父函数处理异常可以处理,但是如果没有祖父函数会发生什么?正如您所提到的,可能有一个uncaughtExceptionHandler,但我觉得依赖它是不自然的,根据我的理解,感觉就像uncaughExceptionHandler 存在,以防引发未处理的错误。我对此的看法很可能是 100% 错误的。
    猜你喜欢
    • 2020-12-19
    • 2021-12-05
    • 2021-04-07
    • 2013-06-27
    • 1970-01-01
    • 1970-01-01
    • 2016-08-18
    • 2011-08-25
    • 1970-01-01
    相关资源
    最近更新 更多