node事件循环
浏览器事件循环见:https://www.jianshu.com/p/64bbefbe5ae5。
参考:http://lynnelv.github.io/js-event-loop-nodejs
nodejs中的eventloop 和 浏览器中的eventloop 不一样。
node事件循环图例:
https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/
各阶段解释:
-
timers: this phase executes callbacks scheduled by
setTimeout()
andsetInterval()
. //此阶段执行由 setTimeout 和 setInterval 调度的回调。 -
pending callbacks: executes I/O callbacks deferred to the next loop iteration. //执行 延迟到下一个循环迭代的 I/O 回调。
-
idle, prepare: only used internally.
-
poll: retrieve new I/O events; execute I/O related callbacks (almost all with the exception of close callbacks, the ones scheduled by timers, and
setImmediate()
); node will block here when appropriate. //检索新的I/O事件;执行与I/O相关的回调(除了close回调、setTimeout调度的回调和setImmediate())之外的几乎所有回调;节点将在适当的时候阻塞这里。 -
check:
setImmediate()
callbacks are invoked here. //此处调用setImmediate回调。 -
close callbacks: some close callbacks, e.g. `socket.on('close', ...)
使用setImmediate的目的是不阻塞当前操作,如下不会阻塞for循环:
trigger(topic,params){
if(!this.eventMap[topic]){
return;
}
this.eventMap[topic].forEach(item=>{
// cb();
item.cb && setImmediate(()=>{item.cb(params)})
})
}
node 微任务执行时机:六个阶段中的任意阶段执行完成,都会执行微任务队列中的任务
image.png例子:
//第一个事件循环,timers中执行
setTimeout(()=>{
console.log('timer1')
// 此处是第二个事件循环,同样是在timers阶段执行
setTimeout(function(){
console.log(11111)
Promise.resolve().then(function() {
console.log('222')
})
},0)
Promise.resolve().then(function() {
console.log('promise1')
})
}, 0)
//第一个事件循环,timers中执行
setTimeout(()=>{
console.log('timer2')
Promise.resolve().then(function() {
console.log('promise2')
})
}, 0)
执行结果:
image.png
理解node 事件循环
function checkFund(){
if(Math.random()<.5){
return {msg:'success'}
}else{
throw new Error('error');
}
}
// 可以捕捉到error,因为处于一个事件循环中
try{
for(let i=0;i<10;i++){
checkFund();
}
}catch(e){
console.log('catch,',e);
}
当使用异步
function checkFund(){
setTimeout(()=>{
if(Math.random()<.5){
return {msg:'success'}
}else{
throw new Error('error');
}
})
}
// 无法捕捉到error,因为处于不同的事件循环中,此时会将error抛到全局,非常不安全
try{
for(let i=0;i<10;i++){
checkFund();
}
}catch(e){
console.log('catch,',e);
}
node官方推荐的error-first回调
function checkFund(cb){
if(Math.random()<.5){
cb(null,{msg:'success'})
}else{
cb(new Error('error'))
}
}
for(let i=0;i<10;i++){
checkFund((err,res)=>{
if(err){
console.log('err')
}
})
}