- 异步回调 首先我们先看一个简单的异步回调的代码例子
function asyncFun(callback) {
setTimeout(() => callback('success'), 300);
}
asyncFun(function (e) {
console.log('end', e);
})
我们首先定义了一个异步函数asyncFun,接受一个函数参数用于在setTimeout中异步执行,这个简单的例子没什么好说的。 但是如果在异步函数中需要跑出了一个错误呢?
function asyncFun(callback) {
setTimeout(() => {
if (Math.random < 0.5)
callback('success');
else
throw new Error('fail')
}, 300);
}
try {
asyncFun(function (e) {
console.log('end', e);
})
} catch (err) {
console.log('err', err)
}
这样执行可以成功catch到错误吗?
答案是并不可以,全局报错了。
因为异步调用,函数真正执行抛出错误的地方已经脱离了原来方法的调用栈,通过node.js的事件循环触发执行的。
那要抛出错误,并在外面处理错误应该如何操作?
function asyncFun(callback) {
setTimeout(() => {
if (Math.random < 0.5)
callback('success');
else
callback(new Error('fail'))
}, 300);
}
asyncFun(function (e) {
if (e instanceof Error) {
console.log('errHere', e)
} else {
console.log('successs', e)
}
})
错误也通过callback抛出。现在的执行结果如下:
可以正常处理错误了。
但是这需要调用方去判断参数类型,做相应的处理。有点过于繁琐了。
所以node.js有一个关于回调函数的约定:error-first 就是如果出现error,error都是作为callback的第一个参数返回:
function asyncFun(callback) {
setTimeout(() => {
if (Math.random < 0.5)
callback(null, 'success');
else
callback(new Error('fail'))
}, 300);
}
asyncFun(function (e) {
if (e) {
console.log('errHere', e)
} else {
console.log('successs', e)
}
})
这样函数调用的时候会方便很多。
- 事件循环
Event Loop是Node.js里面很重要的概念。
是Javascript单线程同时能保证效率的有效办法。 这里我们先不讨论EventLoop中宏任务,微任务等相关概念。我们先模拟实现一个简单的Event Loop。
const eventLoop = {
queue: [],
loop: function () {
if (this.queue.length) {
const callBack = this.queue.shift();
callBack();
}
setTimeout(this.loop.bind(this), 100)
},
add: function (callBack) {
this.queue.push(callBack);
}
}
eventLoop.loop();
setTimeout(() => console.log('111'), 300);
setTimeout(() => console.log('222'), 600);
输出的结果如下:
以上简单的描述了Node.js中的异步回调和事件循环。