在学习的时候,视频里只是说了下【错误处理中间件只能捕获同步异常,不能捕获异步异常】,然后就开始讲怎样来捕获异步异常。但是没有举一个没有成功捕获异步异常的例子来甩在我的脸上,所以就陷入了怀疑的状态,然后开始了自己下面的测试。(可能是有点钻牛角尖吧)
首先呢,先寻摸个异步处理,第一想到的就是定时器
setInterval和setTimeout
前者是每隔多久调用一次;后者是隔多久后调用一次就不再调用。
先来个同步异常,顺便测下定时器程序写对了么
const express = require('express');
const app = express();
app.get('/demo', (req, res, next) => {
//当访问/demo时,3秒后执行箭头函数,来测试下这个定时器是正常的
setTimeout(() => {
console.log('来了来了');
}, 3000);
//自己new了个错误,然后通过throw抛出异常,这个异常的抛出是随着对/demo的访问而触发的
//也就是说是同步的,即刻触发
throw new Error('同步异常');
})
//错误处理中间件。没有指定匹配路径就默认是/也就是根目录
//所有的路径访问都会经过根目录,所以也可以认为匹配所有请求
app.use((err, req, res, next) => {
//这里使用错误对象err的message属性来拿到异常/错误信息
res.status(500).send('use捕获到了异常' + err.message);
})
app.listen(3000, () => {
console.log('服务器已启动!');
})
powershell中使用nodemon来执行本脚本文件,结果如下:
地址栏访问/demo,页面先呈现出:捕获到同步异常 ;3秒后powershell中出现:来了来了。结果说明:同步异常可以被错误处理中间件正常捕获,定时器也可以正常执行。
下面来使用setTimeout来制造【异步异常】,看看错误中间件能否捕获到错误信息。
const express = require('express');
const app = express();
app.get('/demo', (req, res) => {
setTimeout(() => {
console.log('来了来了');
//当访问/demo时,3秒后抛出异常
throw new Error('由定时器抛出的异步异常');
}, 3000);
})
app.use((err, req, res, next) => {
res.status(500).send('use捕获到了异常:' + err.message);
})
app.listen(3000, () => {
console.log('服务器已启动!');
})
nodemon执行脚本,结果如下:
发现页面的红框区域里并没有显示出错误信息,而是直接在控制台中报错了,同时页面呈现出访问的网页出错了。说明错误处理中间件并没有捕获到定时器中抛出的异常。
这不就是说明【错误处理中间件不能够捕获异步异常/错误信息吗】
因为错误处理中间件(这里的use)的第一个请求路径参数省略,也就是/,根目录;每个请求都会先走根目录,意味着use是对所有的请求做异常捕获,但是是在有请求时才触发,像上面的请求时没有错误,请求之后3秒出现了错误,但是没有捕获到。这时的use可以视为已经退下了,所以出现了异常也不能捕获。
解决上面这个问题就是要当出现异常时,重新唤醒错误处理中间件。借助next()来对错误处理中间件进行“唤醒”,告诉它有错误了,把错误以next(error)的方式进行传递,让其对此error进行捕获。
const express = require('express');
const app = express();
//对express对象app的get方法添加next参数,用于错误信息的传递
app.get('/demo', (req, res, next) => {
setTimeout(() => {
console.log('来了来了');
//声明一个变量err来存放异常错误
let err = new Error('由定时器抛出的异步异常');
//使用next对异常错误进行传递,‘唤醒’错误处理中间件
next(err);
}, 3000);
})
app.use((err, req, res, next) => {
res.status(500).send('use捕获到了异常:' + err.message);
})
app.listen(3000, () => {
console.log('服务器已启动!');
})
执行脚本,地址栏访问http://localhost:3000/demo,结果如下:
访问/demo,3秒后控制台输出“来了来了”,然后页面正常输出捕获到的错误信息。也就是说next(error)可以触发错误处理中间件来对异步产生的错误信息进行获取。