1

假设以下场景:

//Where "e" is a global object in the app  
e = new EventEmitter;  

...  

//at some place in the app code I'm adding Listener 1
e.on('myEvent', function() {console.log('Listener 1)});  

...  

//at another place in the app code I'm adding Listener 2
e.on('myEvent', function() {console.log('Listener 2)});  

...  

//at another place in the app code I'm adding Listener N
e.on('myEvent', function() {console.log('Listener N)});  

...  

//finally in some place I'm emitting "myEvent"
e.emit('myEvent', p1, p2);  

在执行“e.emit('myEvent',p1,p2)”的那一刻,我的代码控制着Node主线程(而不是事件循环)。并且“emit”函数是一个同步函数,因此“emit”此时正在调用每个附加到“myEvent”的监听器(在上面的示例中为 N 个监听器)。因此,实际上,调用“e.emit('myEvent', p1, p2)” 等价于在传统的命令式范式中进行以下调用:

Listener1(p1,p2);
Listener2(p1,p2); 
... 
ListenerN(p1,p2);  

如果 N 很大,我会阻塞事件循环,导致我当前的代码控制主线程,而不是事件循环。

这种情况是真实的和可能的吗?是因为这个原因,默认情况下 Node.js 最多有 10 个侦听器吗?

提前致谢!

4

1 回答 1

2

由于 Javascript(无需手动创建子进程)是单线程的,因此您在代码中执行的所有操作都意味着它是按顺序执行的。语言本身是同步的。如果您使用 EventEmitter 添加侦听器,它仍然会在您添加它们时一个接一个地执行所有内容。有可能用一堆手动事件发射来阻塞 Node,但这与有一个while(true)循环是一样的,它会产生类似的结果。EventEmitter 在那里,只是为了有可能使用与内置模块相同的模式。大致相当于 EventEmitter 如下:

var handlers = [];

function addHandler(fn) {
  handlers.push(fn);
}

function emit() {
  for (var i = 0; i < handlers.length; i++) {
    handlers[i]();
  }
}

// Add a bunch of handlers
addHandler(function(){console.log('foobar 1');});
....
addHandler(function(){console.log('foobar N');});

// Fire the event
emit();

异步部分是 OS 和 Node 的结合,它使您能够将文件读取、缓冲等任务委托给 OS 本身,这基本上是在另一个线程中完成的,让 Node 可以自由地运行事件循环。当操作系统向 Node 触发文件读取完成的事件时,它会执行您在 JS 中编写的必要修改。在运行完成文件读取的处理程序时,整个事件循环仍然停止,因为任何时候都有一个 JS 执行实例。

文档中:

默认情况下,如果添加了超过 10 个侦听器,EventEmitters 将打印警告。这是一个有用的默认值,有助于发现内存泄漏。显然不是所有的发射器都应该限制在 10 个。

希望它至少清除了一些东西。

于 2012-01-05T12:47:00.630 回答