警告:可能的EventEmitter - 运行`foundation new`时出现节点警告

时间:2016-08-31 16:14:12

标签: node.js zurb-foundation

每次我在CLI中运行foundation new以启动新的Foundation项目时,我都会收到很长的Node警告列表:

(node:15500) Warning: Possible EventEmitter memory leak detected. 11 error listeners added. Use emitter.setMaxListeners() to increase limit
(node:15500) Warning: Possible EventEmitter memory leak detected. 11 error listeners added. Use emitter.setMaxListeners() to increase limit
(node:15500) Warning: Possible EventEmitter memory leak detected. 11 error listeners added. Use emitter.setMaxListeners() to increase limit
(node:15500) Warning: Possible EventEmitter memory leak detected. 11 error listeners added. Use emitter.setMaxListeners() to increase limit
(node:15500) Warning: Possible EventEmitter memory leak detected. 11 error listeners added. Use emitter.setMaxListeners() to increase limit
(node:15500) Warning: Possible EventEmitter memory leak detected. 11 error listeners added. Use emitter.setMaxListeners() to increase limit
(node:15500) Warning: Possible EventEmitter memory leak detected. 11 error listeners added. Use emitter.setMaxListeners() to increase limit
(node:15500) Warning: Possible EventEmitter memory leak detected. 11 error listeners added. Use emitter.setMaxListeners() to increase limit
(node:15500) Warning: Possible EventEmitter memory leak detected. 11 error listeners added. Use emitter.setMaxListeners() to increase limit
(node:15500) Warning: Possible EventEmitter memory leak detected. 11 error listeners added. Use emitter.setMaxListeners() to increase limit
(node:15500) Warning: Possible EventEmitter memory leak detected. 11 error listeners added. Use emitter.setMaxListeners() to increase limit
(node:15500) Warning: Possible EventEmitter memory leak detected. 11 error listeners added. Use emitter.setMaxListeners() to increase limit
(node:15500) Warning: Possible EventEmitter memory leak detected. 11 error listeners added. Use emitter.setMaxListeners() to increase limit
(node:15500) Warning: Possible EventEmitter memory leak detected. 11 error listeners added. Use emitter.setMaxListeners() to increase limit
(node:15500) Warning: Possible EventEmitter memory leak detected. 11 error listeners added. Use emitter.setMaxListeners() to increase limit
(node:15500) Warning: Possible EventEmitter memory leak detected. 11 error listeners added. Use emitter.setMaxListeners() to increase limit
(node:15500) Warning: Possible EventEmitter memory leak detected. 11 error listeners added. Use emitter.setMaxListeners() to increase limit
(node:15500) Warning: Possible EventEmitter memory leak detected. 11 error listeners added. Use emitter.setMaxListeners() to increase limit
(node:15500) Warning: Possible EventEmitter memory leak detected. 11 error listeners added. Use emitter.setMaxListeners() to increase limit
(node:15500) Warning: Possible EventEmitter memory leak detected. 11 error listeners added. Use emitter.setMaxListeners() to increase limit
(node:15500) Warning: Possible EventEmitter memory leak detected. 11 error listeners added. Use emitter.setMaxListeners() to increase limit
(node:15500) Warning: Possible EventEmitter memory leak detected. 11 error listeners added. Use emitter.setMaxListeners() to increase limit

节点编号始终不同,但警告和警告数始终相同。我该如何解决这个问题?

在这些警告显示之后,其他所有内容似乎都运行正常并且项目已创建。我不确定我是否应该担心这些警告。

1 个答案:

答案 0 :(得分:2)

在关于EventEmitter memory leaks的博客文章中找到此资料,但在此处发布详细信息,因此此答案不是仅限链接的答案。我不相信材料本身,只找到它并创建一个答案,以便Stackoverflow可以看到它。

在node.js和io.js中,您最终会看到以下错误消息:

  

(节点)警告:检测到可能的EventEmitter内存泄漏。 11 a   听众补充道。使用emitter.setMaxListeners()来增加限制。

何时会发生泄漏? 如果连续添加事件处理程序而不删除它们,则会发生泄漏。当您多次使用单个发射器实例时会发生这种情况。让我们创建一个返回流中下一个值的函数:

function next(stream) {
  // if the stream has data buffered, return that
  {
    let data = stream.read()
    if (data) return Promise.resolve(data)
  }

  // if the stream has already ended, return nothing
  if (!data.readable) return Promise.resolve(null)

  // wait for data
  return new Promise(function (resolve, reject) {
    stream.once('readable', () => resolve(stream.read()))
    stream.on('error', reject)
    stream.on('end', resolve)
  })
}

每次在流上调用next()时,都会在可读,错误和结束时添加处理程序。在第11个下一个(流)调用中,您将收到错误消息:

(节点)警告:检测到可能的EventEmitter内存泄漏。 11听众补充道。使用emitter.setMaxListeners()来增加限制。

您不断向错误添加处理程序并结束,但尚未删除它们,即使数据已成功读取且这些处理程序不再相关。

清理事件处理程序

清理处理程序的正确方法是确保在promise解析后,添加了0个事件处理程序:

return new Promise(function (resolve, reject) {
  stream.on('readable', onreadable)
  stream.on('error', onerror)
  stream.on('end', cleanup)

  // define all functions in scope
  // so they can be referenced by cleanup and vice-versa
  function onreadable() {
    cleanup()
    resolve(stream.read())
  }

  function onerror(err) {
    cleanup()
    reject(err)
  }

  function cleanup() {
    // remove all event listeners created in this promise
    stream.removeListener('readable', onreadable)
    stream.removeListener('error', onerror)
    stream.removeListener('end', cleanup)
  }
})

使用此方法,每个promise解析后都不会发生事件发射器泄漏,净更改事件处理程序为0。

并发处理程序

如果您想在同一个发射器上使用多个侦听器,该怎么办?例如,您可能有很多函数正在侦听同一个发射器:

doThis1(stream)
doThis2(stream)
doThis3(stream)
doThis4(stream)
doThis5(stream)
doThis6(stream)
doThis7(stream)
doThis8(stream)
doThis9(stream)
doThis10(stream)
doThis11(stream)
doThis12(stream)
doThis13(stream)

如果上面的所有函数都为数据事件添加了处理程序,那么您将获得相同的泄漏错误消息,但您知道没有实际的泄漏。此时,您应相应地设置最大侦听器数:

return new Promise(function (resolve, reject) {
  // increase the maximum number of listeners by 1
  // while this promise is in progress
  stream.setMaxListeners(stream.getMaxListeners() + 1)
  stream.on('readable', onreadable)
  stream.on('error', onerror)
  stream.on('end', cleanup)

  function onreadable() {
    cleanup()
    resolve(stream.read())
  }

  function onerror(err) {
    cleanup()
    reject(err)
  }

  function cleanup() {
    stream.removeListener('readable', onreadable)
    stream.removeListener('error', onerror)
    stream.removeListener('end', cleanup)
    // this promise is done, so we lower the maximum number of listeners
    stream.setMaxListeners(stream.getMaxListeners() - 1)
  }
})

这允许您确认限制并控制事件处理,同时允许node.js在发生实际泄漏时打印错误消息。

帮助编写更好的代码!

如果您只是.setMaxListener(0),那么您可能会在不知不觉中泄漏。如果您看到使用.setMaxListeners(0)的任何代码(特别是开源),请发出拉取请求来修复它!不要做捷径!