使用Node.js Events模块时出现意外同步行为的原因
Node.js Events模块的同步执行问题
代码示例
var events = require('events'); var eventEmitter = new events.EventEmitter(); eventEmitter.on('myEvent', f2); function f1(x, y) { console.log('got', x, y) eventEmitter.emit('myEvent', x, y); eventEmitter.emit('myEvent', x, y); eventEmitter.emit('myEvent', x, y); console.log('done') } var count = 0 function f2(x, y) { count++; console.log('from f2', x, y, count) } f1(1, 2)
实际运行输出
alok@alok-HP-Laptop-14s-cf3xxx:~/tmp/test-node$ node alok.js got 1 2 from f2 1 2 1 from f2 1 2 2 from f2 1 2 3 done
预期输出
got 1 2 done from f2 1 2 1 from f2 1 2 2 from f2 1 2 3
问题原因
Node.js的EventEmitter.emit()方法是同步执行的。调用emit触发事件时,它会立即遍历并执行所有绑定到该事件的回调函数,直到所有回调执行完毕,才会继续执行emit之后的代码。
在你的代码里,三次eventEmitter.emit('myEvent', x, y)会依次同步调用f2,三次f2的执行都会在console.log('done')之前完成,所以实际输出里done会最后出现。
如果要实现预期的异步效果,需要把事件回调的执行放到异步队列里,比如用process.nextTick()或者setImmediate()包裹回调逻辑,示例修改如下:
// 修改事件绑定部分 eventEmitter.on('myEvent', (x, y) => { process.nextTick(() => f2(x, y)); });
这样emit会立即返回,console.log('done')先执行,待当前事件循环结束后,再依次执行f2的三次调用,就能得到预期的输出顺序。
内容的提问来源于stack exchange,提问作者Alok
相关产品推荐
相关产品推荐

