javascript - 为什么这个简单的基于数组的事件发射器顺序敏感?

标签 javascript arrays push eventemitter

如果事件处理程序前面有“.once”事件处理程序,则简单事件发射器不会触发事件处理程序。无法理解为什么会这样。

const emitter = (host = {}, listeners = {}) => Object.assign(host, {
  emit (event, data) {
    (listeners[event] || []).forEach(h => h(data))
  },
  on (event, handler) {
    if (!listeners[event]) listeners[event] = []
    listeners[event].push(handler)
    return () => host.off(event, handler)
  },
  once (event, handler) {
    if (!listeners[event]) listeners[event] = []
    listeners[event].push(function h () {
      handler(...arguments)
      host.off(event, h)
    })
  },
  off (event, handler) {
    const i = (listeners[event] || []).findIndex(h => h === handler)
    if (i > -1) {
      listeners[event].splice(i, 1)
      if (!listeners[event].length) delete listeners[event]
    }
  }
})

// EXAMPLE

const e = emitter()

e.once('msg', msg => {
    console.log('once.msg: ', msg)
})

e.on('msg', msg => { // <- not firing
    console.log('on.msg: ', msg)
})

e.on('msg', msg => {
    console.log('on_1.msg: ', msg)
})

e.emit('msg' ,'See me?')

第一个“on.msg”处理程序根本不会触发,但是如果“once.msg”处理程序移到其他两个处理程序下方,一切都会顺利触发,这是为什么?

最佳答案

这是因为 (listeners[event] || []).forEach(h => h(data)) 将使用从 0 开始并递增的索引器它为每个项目。当您删除一个项目时(当调用 once 调用 off 时)索引是错误的,实际上会跳过行中的下一个项目。

最简单的补救方法是复制事件:

(listeners[event] || []).slice().forEach(h => h(data));

关于javascript - 为什么这个简单的基于数组的事件发射器顺序敏感?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49046149/

相关文章:

git - GIT 命令的简单序列

javascript - 如何用QUnit和Sinon模拟cookie?

javascript - Angular Directive(指令)数据绑定(bind)无法正常工作

java - 奇怪的 IndexOutOfBound 错误

javascript - 在 Javascript 中反转对象数组

git - 用于推送的 Git native 协议(protocol)或 SSH 协议(protocol)之间的区别

git - git push 如何处理积压的工作

javascript - 如何减少并改进丑陋的 JavaScript 代码?

php - Ajax/PHP 值不会增加多次

c# - 将多波段 16 位 tiff 图像转换为 8 位 tiff 图像