Javascript 在异步回调中捕获try错误

Javascript 在异步回调中捕获try错误,javascript,express,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', (

我正在使用回调在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)
  }
}
从中可以明显看出,它使用标准的节点样式回调。在标准节点样式回调中,传递给您提供的回调的第一个参数是错误或
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()
        }
      })
    }
  })
}
module.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)
    })
}

你在评论中说:


我的实际代码有点复杂,所以我试图通过使用
try
避免重复调用
if(err)
next(err)
。在这里处理错误的更好方法是什么(不太冗长)

不幸的是,这就是节点样式回调的本质。一个选择是为自己提供一个过滤函数,让所有这些结果都通过它,这样就有了常见的错误处理代码

<强>但:您可以考虑使用一个“允诺”节点样式回调的LIB,这样您就可以使用承诺,用其链接机制来完成,这使得集中错误处理成为可能。(一个是这样的包,但还有其他包。)对于“promisified”版本的

客户端。选择
客户端。设置
,等等,该代码可能如下所示:

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()
        }
      })
    }
  })
}
module.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)
    })
}
注意错误处理在最后是如何合并的;如果
客户端出现错误。选择
,则跳过
回调,并将控制传递到
捕获
。如果没有,则执行
,然后执行
回调,并执行
客户机.set
,由此产生的任何错误也将转到该
catch

这也为使用ES2017的
async
/
wait
以同步方式编写异步代码打开了大门:

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 = {
  // ...
}

我的实际代码有点复杂,所以我试图避免调用if(err),然后使用try返回next(err)。在这里处理错误的更好方法是什么(不太冗长)?*尽量避免重复调用应该调用的if(err)和next(err)read@S.Schenk:不幸的是,这就是节点样式回调的本质。我在答案的末尾添加了一条建议。回顾您的第一段代码,我还将添加另一条if,并在client.set调用中返回next(err)。这也更好地说明了为什么您应该避免回调。@S.Schenk:不错,完成了。但请注意,我们仍然在基于承诺的解决方案中使用回调(从某种意义上说,在
async
/
wait
解决方案的封面下)。它只是更具整合性和可组合性,等等。