I've been learning Javascript online and have recently started to put it to use on a website. I'm still a little confused about what might be the most efficient/performant ways to do things, though. A few questions with that in mind...
If a webpage has multiple click events in different sections, each doing something different, one event listener in the body tag — with multiple if/else statements — would be the most efficient way to handle them all. Is that correct?
Is the search method a good way to handle if/else statements in this case? For example:
if (event.target.className.search("js-tab") !== -1) {
// do something
} else if (event.target.className.search("js-dropdown") !== -1) {
// do something else
}
The ID performance only applies to actually finding an element, right? There wouldn't be a difference between event.target.className.search and event.target.id.search, would there? (assuming there aren't an insane amount of class names to search through on that element). I'm currently using className for sections that have the same functionality (multiple tabbed sections on the same page, for example). I suppose I could just as easily use the or operator if it made a difference, like so:
if ((event.target.id.search("js-tab-one") !== -1) || (event.target.id.search("js-tab-two") !== -1))
When there are multiple elements that a click event could potentially be on (an icon inside of an anchor link, for example), how much of a performance hit is it to add additional if/else statements (i.e. check the tag type, and if it's not the a tag, move up)? I recently refactored my css so that my icons were set to width: 100% and height: 100% (ensuring that the click was always happening on the same element every time), but I wonder how much of a performance boost (if any at all) I actually got by doing this?
If a webpage has multiple click events in different sections, each
doing something different, one event listener in the body tag — with
multiple if/else statements — would be the most efficient way to
handle them all. Is that correct?
No. It's useful for handling events on elements that you add dynamically, but not so much for regular events.
Handling all the events in the body means that you will handle all the events. Every click that happens goes through your code to see if it comes from one of the elements that you are interested in.
Is the search method a good way to handle if/else statements in this
case?
No. The search method uses a regular expression, not a string, so the string will be parsed to create a RegExp object. Then a search is done using the regular expression, which is slower than a normal string search, and can give unexpected results.
To look for a string in another string you should use the indexOf method instead. You should however be aware that it will look for a match anywhere in the string, not matching whole class names. It will for example find "all-head" when the element has the class "small-header".
The ID performance only applies to actually finding an element, right?
Yes.
When there are multiple elements that a click event could potentially
be on (an icon inside of an anchor link, for example), how much of a
performance hit is it to add additional if/else statements (i.e. check
the tag type, and if it's not the a tag, move up)?
That means that every click event will have to go through the extra if statements.
If you bind the event to the element instead, you know that the event happened inside that element and you don't have to know which element did actually catch it.
A lot of what you're asking is subjective though and it fits in the context that is trying to happen. So there might be a reason why the below might be not good (as another commenter said, don't prematurely optimize). But there are some programming techniques that can be said about what you have done, namely modularity. There's a few performance considerations but they mostly revolve around writing good code:
1) it really depends on your handler, if you intend to delete and add DOM elements, this can be better because you watch the document instead of tying in a new click handler to each element. but this can be bad because its not modular if you have it do too much stuff. But if its just looking at the state, then this is not really good performance wise....
2) i wouldn't say that the search has any impact on the if else's, but in considering optimization of this particular situation you describe later on, I wouldn't do that. As each time you go through each if-else you end up doing another search and it can add up in the long run if you have a lot of if-elses in the way.
3) there shouldn't be a difference but why search in an id string? unless your id string is part of some unholy long part like musical-js-tab-one-musical-tab which I wouldn't suggest to use as an id like this anyway, you should split it up, you shouldn't tie functionality like that, use classes instead like class='musical' id='js-tab-one' since id's should describe a singular object on the page.
4) everytime you add an if-else, no matter how small it is, is another computer cycle and a little bit more memory. and it can add up, just attach your click handler by tag and by class at this point and let the browser decide to optimize it.
Related
I'm working on a software that got quite huge over many years and we've noticed there are many buttons (or clickable elements like <a> and <img>) that aren't safe from double clicks. Since the software is running on sometimes quite laggy hardware (with touch screens that might bug out and register double clicks for no apparent reason) I'd like to implement some kind of global solution for it.
My first thoughts were:
Global click listener that gets the click event, processes it and starts a cooldown on that specific element. If another click event is registered before the cooldown is over, it'll just block the event.
Changing the click() prototype method of a button or something. I'm not that good with plain JS but I've done something like that for plugins before so I know at least conceptually how that works.
Adding a directive that can be inserted into existing elements which need double click protection. This would probably be the "scalpel" method, even though people might just forget to add it. Sadly I have no idea whether my idea is actually possible with directives as I've never implemented one before.
Something like a class that can be inherited which handles all clicks. Might be possible to implement together with solutions (1) and/or (2).
Do you have a direction you can point me to to investigate further? Is some kind of global handling for this a good idea at all? Are any/all of the solutions possible at all?
I'm trying to understand the best way to optimize performance in JavaScript. To simplify, I have some code where a bunch of buttons are each associated with a specific element, and I need to be able to make changes to both the button and its associated element whenever a button is clicked.
I have been told it is better to consolidate event handlers with event delegation where you can. I've also been told if I can avoid querying the DOM over and over for the same element, better to do it just once and store that for later. But in this case, it seems like I need to do one or the other, so I'm wondering which is more costly? Currently I have the following code that runs once to set things up:
buttons.forEach((button) => {
const area = document.querySelector(`#${button.getAttribute('aria-controls')}`);
button.addEventListener('click', (e) => {
// do some things with "area" and "button"
});
});
Obviously this creates an individual listener for each button, so I was thinking I could rewrite it like this:
document.addEventListener('click', (e) => {
if(e.target.classList.contains("button-class")) {
const area = document.querySelector(`#${e.target.getAttribute('aria-controls')}`);
// do some things with "area" and "button"
}
});
But is this worth the trade off that now every time a button is clicked I have to query for the associated "area" element again? Does the answer change depending on how many buttons I have or how often they are likely to be clicked? Is there some third answer that is more optimal than either of my solutions? Apologies if this is a really obvious and stupid question, but I've been googling and looking through other Stack Overflow questions and really can't find anything to answer this.
which is more costly?
As you already noticed, it's a trade-off. The costs you need to compare are respectively
the execution time taken for initialisation
the execution time taken of each click handler
the memory required to keep state
For just a few buttons, that are clicked in normal web flows (and not, say, an APM testing tool), it really doesn't matter.
The second option is better. The impact of having many listeners is far more than a rare DOM query on every click, and you can also cache those lookups. You also probably don't need to do the lookup on document and could likely be more specific on what node the lookup should start at, which would make the impact far more trivial than doing a full DOM traversal; you could at least use .getElementById, again, to greatly improve performance of that lookup.
I highly doubt you have a situation where they are clicking enough for it to matter, but listener performance impact can be massive and hard to track down and sneak up on you when you aren't expecting it, and do things like silently prevent things from being garbage collected. Minimizing them is more important than caching lookups on a click.
I have a chrome extension that modifies the DOM based on keywords. The problem is, for websites like twitter that have an infinite scroll, I need a way for my function to keep firing as the user scrolls through the page.
Is .livequery() the only way to do this or is there a better way?
Right now all of the logic is plain JavaScript/Jquery, but I'm open to using a framework like Angular if that's the best way to do it.
I have several functions that interact -
1) a hide() function that adds a class to divs containing words I want hidden
2) a walk() function that walks the DOM and identifies divs to call hide() on
3) walkWithFilter() function that gets words to filter from localstorage and calls walk() function
The last function walkWithFilter() is called in a window.onload() event
It seems like the onScroll event would be a natural match for this. The trick would be that you'd need to keep track of what's already been processed to avoid reprocessing old content. If you're assuming that the user is always exposing new content below the existing content, that could be as simple as keeping a pointer to the last processed item and restarting the walkWithFilter method from there. That doesn't seem like an entirely safe assumption to me, though.
If you want to be more robust in that regard, you could try a virtual DOM approach: you maintain a copy of the DOM as you last saw it, compare it to the DOM as it currently exists, and take a diff. I know there are a bunch of premade libraries for this kind of thing, but I haven't used any and can't recommend a specific one (the link just goes to the first example that showed up in Google). It also doesn't appear to be overly burdensome to roll your own, if you're so inclined.
I recently saw a html page, that i thought the id of several html tags was the same, then I realized the ids are unique but it raises the question that what could have happened if the page actually used several tags
As i have heard id attribute of every html tag(if it has one) must be unique,
now i wonder what happens if it is not the case??
what possible errors can it cause?
does different browsers show different reactions for this issue?
does javascript and jquery codes that use duplicated ids run on both tags or what?
Duplicate ids can have various different effects. Which you experience will depend on the method you use to try to access them (and possibly also from browser to browser).
You'll affect all of them
You'll affect the first one
You'll affect the last one
You'll get a collection instead of an element, try to treat it like an element and get an error
Duplicate ids are not allowed in HTML. Don't make trouble for yourself. Use classes for groups and ids for unique identifiers.
Change them as soon as possible, to save a lot of headache in the future. For elements with same property use classes
About your queries,
Now i wonder what happens if it is not the case??
Well, the HTML is not a valid one anymore. Now a days it doesn't hurt much but still not preferred.
What possible errors can it cause?
Errors are little bit hard to predict. But with jQuery you are going to get many.
Does different browsers show different reactions for this issue?
Not sure.
Does javascript and jquery codes that use duplicated ids run on both tags or what?
jQuery will give you trouble. Consider a case where you have two input fields with same ID.
and you try to select second one with out noticing. jQuery('yourID').val() and you'll be selecting the firs value instead. Like this there are a lot of possibilities.
As you said, HTML id, per specs, must be unique. If one where to put duplicated id, the js behavior relative to those ids will be unpredicatable, and could even change between 2 calls.
Any js call on one id (jquery or not) will point to one of the id but without guarentee that :
It will be the same every call
It will have the same order between 2 page refresh
It will have the same behavior beween 2 different browser
It will have the same behavior betwween 2 time the same browser
The problems that could emerge depend on how toghtly the js code is coupled to the underlying element DOM structure anw could mostly point to a undefined exception and stop the js execution.
I have a "create" form inside a bootstrap's modal. All my Javascript related with that form uses id's and not classes. Now what i want to do is to create a second form that uses the same Javascript (based on id's as said before). Is there any proper way to achieve that? I know that is a very bad practice to use dublicate id's.
No, there is no proper way to ever duplicate the use of id's. Browser behavior for this is a mixed bag and cannot be relied on.
Use classes instead or create dynamic id's for each form.
Not really, no.
When you use IDs, you're telling the browser that the ID is uniquely available, on the page.
If you have two forms with the same IDs, that means you've broken that guarantee.
An example of where this causes problems is document.getElementById( ).
It will grab the first element it finds.
If there are two, it will only get you the first one.
Another issue:
forms with IDs have a habit of being saved to Window, using that ID (this behaviour isn't 100% standard across every browser with more than 2% usage, globally, today, but it's still pretty common).
Ugly solutions I've seen in this space are things like "my-id-1" "my-id-2", et cetera, where you then access them like: document.getElementById("my-id-" + x);
...really not pretty at all...
...alternatively, you can keep the forms in JS, and just attach them to the page, when you want to switch back and forth.
In this way, they can share IDs, so long as they're never attached to the page at the same time.
document.querySelector("#my-form") === form1; // true
form1.parentNode.replaceChild(form2, form1);
document.querySelector("#my-form") === form2; // true
Again, this isn't going to help you with the built-in form and input namespacing, in any meaningful way, but if that's a feature you are 100% ignoring (not a bad thing to do), this will solve those problems.
Alternatively, you could just move to classes and data-attributes (or just attributes), and life would get easier still...
If you insist on using two forms on one 'page' and share ids between them, you have few options to make it work and be relatively 'clean' about it. Not knowing your technology stack, I can't give a completely relevant answer. However you can do something similar to the below:
HTML
<div id="myFormDiv"></div>
JAVASCRIPT
$("#myFormDiv").load(urlToForm);
You would naturally need your forms to be in separate html files for this to work as there is no way you can reliably use ids on multiple elements in one html file.