在异步回调中捕获try错误

时间:2017-08-31 07:12:22

标签: javascript express

我使用回调在redis db async上设置了一些ip。

我试图捕获错误并通过express将其发送到我的错误处理程序中间件。

我在select方法上故意生成错误,但它并没有发现我的错误。

请参阅以下代码:

module.exports = (req, res, next) => {
  const redis = require('redis')
  const client = redis.createClient()
  try {
    client.select('2d', (err) => { // instead of 2 number, i use '2d' string, to generate an error on purpose
      const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress
      client.set(ip, true, 'EX', 120, (err, rep) => {
        return next()
      })
    })
  } catch (err) {
    err.type = 'SilentSystem'
    next(err)
  }
}

1 个答案:

答案 0 :(得分:3)

documentation of the redis npm package开始,很明显它使用标准的Node-style回调。在标准的Node-style回调中,传递给您提供的回调的第一个参数是错误或null;这就是报告错误的地方和方式。 (您甚至在代码中定义了一个名为err的参数。)它们无法被try/catch捕获,因为控件已经超出了try/catch(实际上已经超出了module.exports = (req, res, next) => { const redis = require('redis') const client = redis.createClient() client.select('2d', (err) => { // instead of 2 number, i use '2d' string, to generate an error on purpose if (err) { // Handle error here err.type = 'SilentSystem' next(err) } else { // Handle success here const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress client.set(ip, true, 'EX', 120, (err, rep) => { if (err) { err.type = 'SilentSystem' next(err) } else { next() } }) } }) } 在错误发生之前很久就发生了它的功能。

所以你要像这样处理它:

if(err)

你在评论中说过:

  

我的实际代码有点复杂,所以我试图避免调用以避免使用next(err)重复调用tryclient.select。在这里处理错误的更好方法(更简洁)是什么?

不幸的是,这就是Node风格回调的本质。一种选择是给你自己一个过滤功能,你通过所有这些结果,所以你的常见错误处理代码就在那里。

但是:你可能会考虑使用一个“宣传”节点式回调的lib,这样你就可以使用promises,完成它们的链接机制,使集中的错误处理成为可能。 (其中一个包是promisify,但还有其他包。)对于client.setmodule.exports = (req, res, next) => { const redis = require('redis') const client = makeNiftyPromiseVersionOf(redis.createClient()) client.select('2d') .then(data => { const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress return client.set(ip, true, 'EX', 120) }) .then(() => { next() }) .catch(err => { err.type = 'SilentSystem' next(err) }) } 等的“已宣传”版本,该代码可能如下所示:

client.select

注意最后如何整合错误处理;如果then中出现错误,则会跳过catch回调并将控制传递给then。如果没有,则会执行client.set回调并执行catch,并且其中的任何错误也会转到async

这也打开了使用ES2017的await / module.exports = (req, res, next) => { (async () => { const redis = require('redis') const client = makeNiftyPromiseVersionOf(redis.createClient()) try { const data = await client.select('2d'); const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress await client.set(ip, true, 'EX', 120) next() } catch (err) { err.type = 'SilentSystem' next(err) } })(); } 以同步方式编写异步代码的大门:

require

附注:我会删除导出函数的const redis = require('redis') module.exports = { // ... } 调用 out ,而是在模块级别执行此操作:

setInterval(function(){
   $("#irack").stop().animate({"left": -30}, 20)
},300);