I read in one of the articles on the web this sentence:
Adding event handlers to each of the 1000 cells would be a major performance problem and, potentially, a source of browser-crashing memory leaks.
But I don't understand it. If for example, I am doing something like this:
const handler = e => // do something
document.querySelectorAll("td").forEach(td => {
td.addEventListener("click", handler);
});
I don't create 1000 functions, they all use the same reference, so what I am missing? What is the problem?
I read in one of the articles on the web this sentence:
Adding event handlers to each of the 1000 cells would be a major performance problem and, potentially, a source of browser-crashing memory leaks.
But I don't understand it. If for example, I am doing something like this:
const handler = e => // do something
document.querySelectorAll("td").forEach(td => {
td.addEventListener("click", handler);
});
I don't create 1000 functions, they all use the same reference, so what I am missing? What is the problem?
Share Improve this question edited Apr 7, 2017 at 11:57 undefined asked Apr 7, 2017 at 11:47 undefinedundefined 6,91413 gold badges53 silver badges102 bronze badges 4-
If I understand, you're worry about memory leaks. The think is that everytime you click one
td
will execute that handler, per click – funcoding Commented Apr 7, 2017 at 11:51 - 3 because you need to bind 1000 events, that is not free. (and in your example, you are binding one event) – epascarello Commented Apr 7, 2017 at 11:55
- Please link the article you were reading to cite the quotation and that we get some context. – Bergi Commented Apr 7, 2017 at 12:03
- sitepoint./… – undefined Commented Apr 7, 2017 at 12:31
4 Answers
Reset to default 5I don't create 1000 functions, they all use the same reference, so what I am missing?
You would still create 1000 function references in the 1000 DOM nodes. This might not seem significant, but the table could grow…
Of course, you are basically right, if you don't create 1000 closures there won't be as many problems. However, do you really have 1000 buttons that all do the same? With closures, it's easy to let them do marginally different things; with only one function you would need to make it dynamically depend on the cell that was clicked (the event target). And when you're doing that already, you could just go ahead and use only a single function reference and event delegation…
The way event delegation works is that you add an event listener in a parent element. When the parent triggers the event, you get a reference of the actual element that triggered the event and then check if that is the element you want to listen to Maybe a code would help you understand it better
// Listen for the event on the parent...
document.getElementById("event-table").addEventListener("click", function(e) {
// '.target' will now give us our actual clicked element
if(e.target && e.target.nodeName == "td") {
// Wooho, a '<td>' node was clicked
console.log("We have our click event delegated!");
}
});
The way it helps is that now, instead of adding a eventListner on each element I can simply attach it to a parent and then check for it's child.
The real use of this functionality is when you want to attach events on some dynamically created elements. Say a row in your table is added dynamically after a database call. In such case, you would have to reattach a event listener to the new node if you're going the route of attaching the event to each node. But if you're using the delegation approach, as the event is attached to the parent, the newly created child node automatically bees a part of the event
It can prove to degrade performance if you attach it to a parent that has many child's, which don't actually are the intended nodes for the event. For eg, if you attach the body node itself and then delegate to the 'td' tags inside it ! In theory it would work for sure but would potentially slow things down.
In JavaScript, events will bubble up the DOM chain. When you click on td
, any event handler on td
will fire, and also on tr
and on table
, etc., all the way up the chain.
The article is telling you to register the event on table
(for example) instead of each td
element.
I don't create 1000 functions, they all use the same reference, so what I am missing? What is the problem?
You are not creating 1000 functions but you are registering 1000 event handlers, which is what the article is advising against. Register one event handler on some parent element, like table
, instead.
Here is a jsFiddle example on how to register one event handler for 1000 table cells.
Maybe an analogy will help you better understand it. Say you have a pany where customers call you and you send them something.
- Attaching a unique event handler to each cell would like having 1000 phone lines, one for each customer and having to hire 1000 employees to man each phone waiting for orders.
- Attaching a single event handler to all of the cells is like still having 1000 phone lines, one for each customer but monitored by a single employee who has to figure out which customer's line is ringing and where to send the stuff. You no longer need 1000 employees but you still have 1000 phone lines.
- Using event delegation is like having a single phone line that all your customers call and a single employee who know where to send their stuff based on the caller id.
Using a single phone line makes your employee much more efficient.