youngwind / blog

梁少峰的个人博客
4.66k stars 385 forks source link

try...catch、express与co错误捕获 #53

Open youngwind opened 8 years ago

youngwind commented 8 years ago

原因

try catch捕获错误这个我原先知道,但是与express和co结合起来的时候我就觉得其中有些微妙的变化,决定好好研究一下。

1. try..catch

JSON.parse('a');
console.log('finish');

这段代码会在执行第一行的时候报错,程序中断,不会执行第二行。

try{
   JSON.parse('a');
} catch(e) {
   console.log(e);
}
console.log('finish');

这段代码会在执行第二行的时候报错,但是错误会被catch捕获,输出错误信息,程序得以继续执行,输出'finish'

ok,下面我们再看看try...catch能不能捕获throw抛出的错误

try{
  throw new Error('错误信息');
} catch(e) {
  console.log(e);
}
console.log('finish');

结果证明是可以的。

然后,我们再看看能不能捕获异步的错误

try{
 setTimeout(function(){
   JSON.parse('a')
  },1000)
} catch(e) {
  console.log(e);
}

console.log('finish')

先输出'finish',1s之后再报错。注意,是报错,而不是输出错误,也就是说,try...catch没法捕获异步错误. 怎么办? node有一个domain模块可以解决这个问题,参考这里,不过看起来老负责了,我好想还用不到,以后再研究。

express错误捕获

ok,接下来我们看看在express里面错误是如何被捕获和传递的。

// 假设我们在访问首页的时候抛出错误
router.get('/', function (req, res, next) {
  throw new Error('访问首页出错');
});

// 然后app.js里面有两个错误处理中间件
app.use(function (err, req, res, next) {
  console.log('经过第一个错误处理中间件');
  next(err);
});

app.use(function (err, req, res, next) {
  console.log('经过第二个错误处理中间件');
  res.status(err.status || 500);
  res.render('error', {
    message: err.message,
    error: err
  });
});

结果发现,首页抛出的错误会先被第一个错误处理中间件捕获处理,然后又传递给第二个错误中间件处理。关于更详细的express里面的错误捕获和传递机制可以参考这里

然后,我们看看如果在首页的地方异步执行的时候报错会怎么样呢?

router.get('/', function (req, res, next) {
  setTimeout(function () {
    throw new Error('异步错误');
  }, 2000)
  res.render('index', {title: 'Express'});
});

执行结果:访问首页正常,不报错。但是2s之后后端报错,程序中断执行。也就是说,这种异步错误,express错误处理中间件是没有办法捕获的。怎么办,我尝试调换一下顺序。

router.get('/', function (req, res, next) {
  setTimeout(function () {
    throw new Error('异步错误');
    res.render('index', {title: 'Express'});
  }, 2000)
});

执行结果:访问首页,延时2s,之后首页访问返回错误,后端报错,程序中断执行。那么,像这种异步抛出的错误,如何让express捕获到呢?下面我们看看co

co

//未完待续......