最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Event listener that is added via addEventListener is being called multiple times - Stack Overflow

programmeradmin1浏览0评论

I am using addEventListener to react to certain events.

From what I read, it is possible to register multiple identical EventListeners on the same EventTarget, and the EventListener will only be called once.

Here's the quote from MDN:

If multiple identical EventListeners are registered on the same EventTarget with the same parameters, the duplicate instances are discarded. They do not cause the EventListener to be called twice, and they do not need to be removed manually with the removeEventListener() method. Note however that when using an anonymous function as the handler, such listeners will NOT be identical since anonymous functions are not identical even if defined using the SAME unchanging source-code simply called repeatedly, even if in a loop. However, repeatedly defining the same named function in such cases can be more problematic. (see Memory issues below.)

I am not sure why this does not happen in this example? Running this code will call the EventListener twice: (Codepen here)

function _callback() { console.log("fnFunction"); }

function init() {
  attachGesture("panel-anchor", _callback);
  attachGesture("panel-anchor", _callback);
}

function attachGesture(sElementId, fnFunction) {
  var oElement = document.getElementById(sElementId);

  function foo() {
    console.log("Foo");
    fnFunction();
  }

  oElement.addEventListener("click", foo, false);
}

window.onload = init;

How can I make sure the EventListener is called only once?

I am using addEventListener to react to certain events.

From what I read, it is possible to register multiple identical EventListeners on the same EventTarget, and the EventListener will only be called once.

Here's the quote from MDN:

If multiple identical EventListeners are registered on the same EventTarget with the same parameters, the duplicate instances are discarded. They do not cause the EventListener to be called twice, and they do not need to be removed manually with the removeEventListener() method. Note however that when using an anonymous function as the handler, such listeners will NOT be identical since anonymous functions are not identical even if defined using the SAME unchanging source-code simply called repeatedly, even if in a loop. However, repeatedly defining the same named function in such cases can be more problematic. (see Memory issues below.)

https://developer.mozilla/en-US/docs/Web/API/EventTarget/addEventListener#Multiple_identical_event_listeners

I am not sure why this does not happen in this example? Running this code will call the EventListener twice: (Codepen here)

function _callback() { console.log("fnFunction"); }

function init() {
  attachGesture("panel-anchor", _callback);
  attachGesture("panel-anchor", _callback);
}

function attachGesture(sElementId, fnFunction) {
  var oElement = document.getElementById(sElementId);

  function foo() {
    console.log("Foo");
    fnFunction();
  }

  oElement.addEventListener("click", foo, false);
}

window.onload = init;

How can I make sure the EventListener is called only once?

Share Improve this question edited Dec 3, 2018 at 12:30 yunzen 33.5k13 gold badges78 silver badges113 bronze badges asked Dec 3, 2018 at 11:55 ShishigamiShishigami 4513 gold badges8 silver badges20 bronze badges 5
  • 2 attach it only once, NOT two times the same listener. Both listeners (which are identical) will be called – Nikos M. Commented Dec 3, 2018 at 11:56
  • From what I read ... where did you read that? – yunzen Commented Dec 3, 2018 at 12:12
  • @HerrSerker developer.mozilla/en-US/docs/Web/API/EventTarget/… – Shishigami Commented Dec 3, 2018 at 12:28
  • I added the quote to your question as it is an important information – yunzen Commented Dec 3, 2018 at 12:30
  • This Codepen might be an option for you – yunzen Commented Dec 3, 2018 at 12:53
Add a ment  | 

3 Answers 3

Reset to default 3

it is possible to register multiple identical EventListeners on the same EventTarget, and the EventListener will only be called once.

It isn't.

If you register the same event handler multiple times, then it will only be called once.

Identical but not === event handlers are not the same event handler.

You need to change your logic to avoid attempting to register identical handlers.

As Quentin already mentioned and is written in the MDN documentation, the event listener functions must be identical to do what you want to achieve.

(emphasize mine)

If multiple identical EventListeners are registered on the same EventTarget with the same parameters, the duplicate instances are discarded.

I tried to use Function.prototype.bind to achieve this, but that returns a copy of the original function and so won't work.

I think you cannot do it without doing your own housekeeping.

"use strict";
console.clear();

function _callback() { console.log("foo fnFunction"); }
function _callback2() { console.log("bar fnFunction"); }

function init() {
  var btn = document.getElementById('btn');
  attachGesture(btn, 'click', _callback);
  attachGesture(btn, 'click', _callback);
  attachGesture(btn, 'click', _callback);
  attachGesture(btn, 'click', _callback2);
  attachGesture(btn, 'click', _callback);
  attachGesture(btn, 'click', _callback);
  attachGesture(btn, 'click', _callback2);
  attachGesture(btn, 'click', _callback);
  attachGesture(btn, 'click', _callback);
}


;(function() {
  var houseKeeping = new Map();
  
  function _attachGesture(element, eventName, callback) {
    if (!houseKeeping.has([element, eventName, callback])) {
      houseKeeping.set([element, eventName, callback], true);
      element.addEventListener(eventName, callback);
    }
  }
  
  window.attachGesture = _attachGesture
})();



window.onload = init;
<button id="btn">Click</button>

Based on what I've read, since you're recreating foo inside attachGesture every time you're calling it, the above-mentioned function foo is pertaining to a different instance of itself every time. Thus, they are not the same (which violates what was mentioned in your MDN reference). Storing a reference to foo somewhere and assigning that one instead should fix the problem.

Simply put, you could try something like this

let _callback = ()=>{ console.log("fnFunction"); }
let foo = undefined;


function init() {
  attachGesture("btn_click", _callback);
  attachGesture("btn_click", _callback);
}

function attachGesture(sElementId, fnFunction) {
  var oElement = document.getElementById(sElementId);
  foo = !foo ? ()=>{console.log('foo!'); fnFunction()} : foo;
  oElement.addEventListener("click", foo);
}

window.onload = init;
<input type="button" id="btn_click" value="the button">

Also, here's a working example :)

发布评论

评论列表(0)

  1. 暂无评论