有没有办法将等待/异步 try/catch 块包装到每个函数?

Posted

技术标签:

【中文标题】有没有办法将等待/异步 try/catch 块包装到每个函数?【英文标题】:Is there a way to wrap an await/async try/catch block to every function? 【发布时间】:2017-05-11 23:39:56 【问题描述】:

所以我正在使用 express.js 并研究在节点 7 中使用 async/await。有没有办法我仍然可以捕获错误但摆脱 try/catch 块?也许是一个函数包装器?我不确定这将如何实际执行函数的代码并调用next(err)

exports.index = async function(req, res, next) 
  try 
    let user = await User.findOne().exec();

    res.status(200).json(user);
   catch(err) 
    next(err);
  

像这样...?

function example() 
   // Implements try/catch block and then handles error.


exports.index = async example(req, res, next) 
  let user = await User.findOne().exec();
  res.status(200).json(user);

编辑:

类似的东西:

var wrapper = function(f) 
    return function() 
        try 
            f.apply(this, arguments);
         catch(e) 
            customErrorHandler(e)
        
    

这会以某种方式处理 try/catch 块但不起作用:

exports.index = wrapper(async example(req, res, next) 
  let user = await User.findOne().exec();
  res.status(200).json(user);
);

有关非异步示例,请参阅 Is there a way to add try-catch to every function in javascript?。

【问题讨论】:

只使用 express-promise 如果不使包装函数异步,就无法包装 await。在这种情况下,为什么不直接使用.then().catch()。什么是await 买你。错误处理需要在那里。您不能只希望它用于其他功能。 我正在寻找在可能需要分叉时删除嵌套的then 语句的方法。上面的代码只是一个示范性的例子。 @Neverlax - 你需要更具体地说明你在问什么。在上面的内容中不需要嵌套的 .then() 处理程序 - 如果需要对多个异步操作进行排序,则可以链接。您无法隐藏错误处理并尝试是傻瓜的差事。 await 的一大缺点是人们倾向于只更改错误处理,而 .then().catch() 对它的需求更为明显。你仍然可以用await 来做,但它需要`try/catch。请使用与您要询问的内容一样复杂的真实代码。 @jfriend00 感谢您的评论。当我问Is there a way that I can still catch errors but get rid of the try/catch block scaffold时,我感觉很清楚 【参考方案1】:

所以,异步函数实际上是承诺,我想出了这个解决方案:

const asyncWrapper = async promise => 
    try 
        return [null, await promise];
     catch (err) 
        return [err];
    
;

const yourAsyncMethod = params => new Promise((resolve, reject) => 
    resolve(params);
);

(async () => 
  // Wrap the executed async method but use the await outside
  const [error, result] = await asyncWrapper(yourAsyncMethod(1));
  
  if (error) 
    // Handle error
  
  console.log(result);
)();

【讨论】:

【参考方案2】:

如果有人更喜欢 async/await 和 Express 特定的方法,那么使用 sn-p 可能会很有用

export function asyncWrap(fn) 
  return async function wrappedFn(req, res, next) 
    try 
      await fn(req, res);
     catch (err) 
      next(err);
    
  ;

可以通过以下方式在路由器中使用

customRouter.get('/', asyncWrap(customController.getCustomListHandler));

【讨论】:

【参考方案3】:

类似的回答here希望能帮到你

const sthError = () => Promise.reject('sth error');

const test = opts => 
  return (async () => 

    // do sth
    await sthError();
    return 'ok';

  )().catch(err => 
    console.error(err); // error will be catched there 
  );
;

test().then(ret => 
  console.log(ret);
);

【讨论】:

【参考方案4】:

是的,您也可以轻松地为异步函数编写这样的包装器 - 只需使用 async/await

function wrapper(f) 
    return async function() 
//         ^^^^^
        try 
            return await f.apply(this, arguments);
//                 ^^^^^
         catch(e) 
            customErrorHandler(e)
        
    

或者你直接使用promises,就像这个例子中更适合表达(尤其是参数的数量):

function promiseWrapper(fn) 
    return (req, res, next) => 
         fn(req, res).catch(next);
    ;

【讨论】:

这确实有效。但是,需要将 async 应用于返回的函数而不是实际的包装函数。您能否进行该编辑以便我可以将其标记为答案?谢谢! 是的,它是一个箭头函数,但普通函数也可以。重要的是它们是正式声明的参数,即promiseWrapper(…).length == 3,用于区分处理程序。 你能帮我解释一下吗,因为我对 Express 和 Javascript 还很陌生,很难理解它是如何工作的。我没有得到这样一个事实,即我们正在返回一个正在执行原始函数 (fn) 的函数,但它在实践中是如何执行的 @ankshukla "事实上我们正在返回一个正在执行原始函数的函数" - 看起来你确实明白了 :-) 不知道还有什么说。您可能想了解一般的闭包?或者您不确定wrapper 是如何应用的?

以上是关于有没有办法将等待/异步 try/catch 块包装到每个函数?的主要内容,如果未能解决你的问题,请参考以下文章

try..catch 没有捕捉到异步/等待错误

在 ExpressJS 响应中返回异步等待 try/catch 抛出错误 [重复]

如何在 JS 中使用 try、catch、.then 链接和异步等待来解决承诺?

为啥使用Try,Catch捕获异常,程序依然Crash

如何使节点 fs 与类异步/等待?

try{ } catch{ } finally{ }