I would like to edit my if else statement in javascript dynamically.
So after one if statement is used, it could be removed. I get this maybe isn't possible but after a search online failed, my curiosity begged me to ask.
For instance:
if (x > 200 && x % 25 === 0) {
doSomething1();
} else if (x > 300 && !inRange) {
doSomething2();
} else if (x > 400 && x % 7 === 0) {
doSomething3();
}
There are eight if else statements within this loop. The loop determines which object to create. There are 2000 objects created over the course of a couple minutes. If on average we reach the fourth statement before it breaks, then there are 8,000 calculations being performed just within this one set of statements.
I want to streamline the script for speed and again, curiosity if we can actually write javascript dynamically without using separate functions etc. After an if statement fails, it is often not required anymore. The next statement could I suppose, include code to remove its predecessor dynamically. This might save 3 or 4 thousand calculations - not huge I know, but worthy of consideration given that there are lots of other things going on as well.
Is there a way to remove them dynamically or does anyone have any tricks or patterns up their sleeves?
Also, even if this is not available in js, what would this be called?
No. And the need for such would indicate poor design.
You should use a conditional expression to determine when which code segment should be run, as you mention. If you pass a certain threshold within your code after which you no longer want a condition to be executed in your loop, why not simply break the loop and have a new code block handling the doSomethingElse clause. If you're using setInterval, that's the point at which you would call clearInterval, and then trigger some new action if necessary. Anyway, running a single (or even a few) simple conditional statement doesn't add much overhead, and isn't likely to be the limiting factor in your optimization anyway.
Ignoring the fact that I doubt this is a bottleneck in modern browsers that JIT the JavaScript (CPUs are very good at predictive branching) as shown because simple number comparison is not going to be expensive even in large iterations with smart predictions once it's compiled.
You can do this by injecting a different function:
checker: function(x) {
if (x > 200) {
doSomething1();
}
else if (x > 300) {
doSomething2();
}
else if (y > 400) {
doSomething3();
}
}
Can be changed to
checker: function(x) {
if (x > 200) {
doSomething1();
}
else if (x > 300) {
doSomething2();
this.checker = smallerChecker;
}
else if (y > 400) {
doSomething3();
}
}
function smallerChecker(x) {
if (x > 200) {
doSomething1();
}
else if (y > 400) {
doSomething3();
}
}
Fundamentally, you simply need to make the behavior injectable, and then you change it however you see fit. Be-it by replacing the function doing the checking outright (the functional way) as I did above, or enabling an object to replace it (the OO way).
Why would you want to remove them dynamically? Altering the code dynamically is unnecessary and a bag of worms that's overdoing it for this situation. You should be using a flag.
I'll answer separately for whether you're trying to skip a large group of if statements, or an individual if statement.
Foreword
As mentioned in the comments on your question, run profiling to make sure you know where your performance problems are!
You mention your aversion to simply using boolean flags to make an if statement not run in your answer. This is fine, and it's what people normally do. This should not be an actual performance concern, and profiling will probably show your performance problems lie elsewhere. If they don't and this boolean flag check is genuinely your bottleneck - you have bigger problems, such as expecting too much from your JavaScript code, or that you didn't use the profiling tool correctly, or misinterpreted its results.
If you're trying to avoid running the body of an if statement, or its conditions, those are a bigger performance concern to you than the boolean flag check itself.
For skipping a large group of if statements
Wrap your bunch of if statements in a condition.
if (runBunchOfIfStatements) {
// all those if statements here
}
When you're past the point of wanting those if statements to run, set the runBunchOfIfStatements flag to false (of course, you should probably pick a more meaningful name than that).
That said, 8 or 9 if statements is a code length issue, and more than likely means nothing at all for performance concerns - unless those if statements happen to involve very intensive checks. If you're worried just because there's a lot of if checks, you're probably looking in the wrong place.
For individual if statements
Say you have only one if statement you want to skip. You had this code in your answer:
} else if (x > 300 && !doneSomething2) {
doSomething2();
doneSomething2 = 1;
}
This is fine. You're just making a tiny check: see the foreword. Look elsewhere for your performance concern. It could be rewritten slightly to more closely follow convention (which I'm about to get to), but in this situation, the change will have negligible impact.
Let's take a situation where there is actually a performance concern here. Suppose that instead of checking x > 300 you're doing something more intensive like calculateSeveralSquareRoots(). Generally, you do take this approach, but you rearrange it like this:
} else if (needCalculations && calculateSeveralSquareRoots() {
// do stuff
needCalculations = false;
}
The difference here is the needCalculations flag comes first, not second. JavaScript's comparison operators have short circuit evaluation. This means that when evaluating a && b, if a is false, b never even gets checked - we already know the result will be false. If the flag comes first, that means calculateSeveralSquareRoots() never gets run, and you save time on the check.
If the flag came second, then you're potentially wasting a lot of time on that function for a condition that might almost always resolve to false anyway thanks to that flag.
So in your original, you could have the flag come before the x > 300 evaluation, just to follow convention. But again... if an if statement like this is a real and significant performance concern for you, then you have bigger issues.
Order them in order of likelihood (so if >400 is most common, check for that first, and if x<200 is next most common, check for that, etc.) The example code is in order of increasing boundaries.
Next, your code doesn't show it and you just imply it, this is in a loop. (And if it isn't a loop, then this isn't a perf issue of interest) You could try fancy loops like Duff's device.
And figuring out what code can be changed to use more native API's is going to make a magical difference, whereas code optimizations like this will likely make only a marginal difference.
If you want it to be dynamic, you could always have a collection of conditions associated with actions and as soon as executed, these gets removed from the collection. However, I doubt it will lead to faster code execution, but you would have to create a jsperf test to know for sure.
DEMO: http://jsfiddle.net/a2ZEj/1/
function doSomethingA() {}
function doSomethingB() {}
var doOperation = (function doOperation() {
var operations = [
{
check: function (someArg) {
return someArg > 100;
},
exec: doSomethingA
},
{
check: function (someArg) {
return someArg > 100 && someArg < 200;
},
exec: doSomethingB
}
];
return function (someArg) {
var i = 0,
len = operations.length,
item;
for (; i < len; i++) {
if ((item = operations[i]).check(someArg)) {
item.exec();
operations.splice(i, 1);
console.log('executed ' + item.exec.name);
return;
}
}
};
})();
doOperation(101); //calls doSomethingA
doOperation(101); //calls doSomethingB
doOperation(101); //does nothing
You can create a method as below and create dynamic conditions
function buildCond(lhv1,rhv1,lhv2,rhv2)
{
var condition1,condition2;
condition1 = condition2 = '';
if(rhv1 !== -1){
condition1 = lhv1 + " == " + rhv1 + " && ";
}
if(rhv2 !== -1){
condition2 = lhv2 + " == " + rhv2 + " && ";
}
return condition1 + condition2;
}
And then call this method with eval to execute
if(eval(buildCond(var1,value1,var2,value2)) === true){
//do stuff
}
Related
I'm new to programming, and In very many cases, i find myself torn whether i should copy paste code to make the program run faster, or gather methods by forcing the program to go through additional loops. I'll give you an example a bit like my current case:
solution1: (copypaste code)
button1.clickevent: saveValue1Method()
button2.clickevent: saveValue2Method()
button3.clickevent: saveValue3Method()
saveValue1Method()
{
doSomethingWithValue1()
buttonlabel.text = "you clicked a button";
doThis();
}
saveValue2Method()
{
doSomethingWithValue2()
buttonlabel.text = "you clicked a button";
doThis();
}
saveValue3Method()
{
doSomethingWithValue3()
buttonlabel.text = "you clicked a button";
doThis();
}
dosomethingwithValue1()
{
mylabel.text = 1;
}
doSomethingWithValue2()
{
mylabel.text = 2;
....
}
doSomethingWithValue3()
{
mylabel.text = 3;
....
}
solution2: (more program instructions)
button1.clickevent: saveValueMethod(1)
button1.clickevent: saveValueMethod(2)
button1.clickevent: saveValueMethod(3)
saveValueMethod(int i)
{
if (i == 1)
{
doSomethingWithValue(1)
}
if (i == 2)
{
doSomethingWithValue(2)
}
if (i == 3)
{
doSomethingWithValue(3)
}
buttonlabel.text = "you clicked a button";
doThis();
}
doSomethingWithValue(int j)
{
if (j == 1)
{
mylabel.text = 1;
...
}
if (j == 2)
{
mylabel.text = 2;
}
if (j == 3)
mylabel.text = 3;
}
Keep in mind this is just a simplified example, and doesn't necessarily make sense. In many cases i would have to loop through a lot of values, not just if 1,2 or 3.
Which concept is good coding?
In general you should follow the DRY principles (don't repeat yourself) and never copy blocks of code.
Factoring your code into common functions will make your code easier to read and maintain and is unlikely to make a significant difference in performance. It is universally considered the "right" way to code.
Even when spending serious time optimizing code for performance, it is rarely a function call that is the main cause of a slowdown and other, much more important aspects of your algorithm or task are usually a much more leveraged way to improve performance. But, please realize that in 99.99% of all code, performance of the actual bytes of code is rarely an issue. So, write your code initially for maximum clarity, reusabilty, readability and maintainability and then, only once you've proven that you actually have a performance problem somewhere and have measured exactly what is causing the problem would you consider reoptimizing your lines of code to make it run faster.
So I'm looking for some advice on the best method for toggling the class (set of three) of an element in a loop ending at 360 iterations. I'm trying to avoid nested loops, and ensure good performance.
What I have:
// jQuery flavour js
// vars
var framesCount = '360'; // total frames
var framesInterval = '5000'; // interval
var statesCount = 3; // number of states
var statesCountSplit = framesInterval/statesCount;
var $scene = $('#scene');
var $counter = $scene.find('.counter');
// An early brain dump
for (f = 1; f < framesCount; f += 1) {
$counter.text(f);
for (i = 1; i < statesCount; i += 1) {
setTimeout(function() {
$scene.removeClass().addClass('state-'+i);
}, statesCountSplit);
}
}
So you see for each of 360 frames there are three class switchouts at intervals. Although I haven't tested I'm concerned for the performance hit here once that frames value goes into the thousands (which it might).
This snippet is obviously flawed (very), please let me know what I can do to make this a) work, b) work efficiently. Thanks :-)
Some general advice:
1) Don't declare functions in a loop
Does this really need to be done in a setTimeout?
for (i = 1; i < statesCount; i += 1) {
setTimeout(function() {
$scene.removeClass().addClass('state-'+i);
}, statesCountSplit);
}
2) DOM operations are expensive
Is this really necessary? This will toggle so fast that you won't notice the counter going up. I don't understand the intent here, but it seems unnecessary.
$counter.text(f);
3) Don't optimize early
In your question, you stated that you haven't profiled the code in question. Currently, there's only about 1000 iterations, which shouldn't be that bad. DOM operations aren't too bad, as long as you aren't inserting/removing elements, and you're just modifying them.
I really wouldn't worry about performance at this point. There are other micro-optimizations you could apply (like changing the for loop into a decrementing while loop to save on a compare), but you gave no indication that the performance is a problem.
Closing thoughts
If I understand the logic correctly, you're code doesn't match it. The code will currently increment .counter as fast as the processor can iterate over your loops (should only take a few milliseconds or so for everything) and each of your "class switchouts" will fire 360 times within a few milliseconds of each other.
Fix your logic errors first, then worry about optimization if it becomes a problem.
Don't use a for loop for this. This will generate lots of setTimeout events which is known to slow browsers down. Use a single setTimeout instead:
function animate(framesCount, statesCount) {
$scene.removeClass().addClass('state-'+statesCount);
if (framesCount) {
setTimeout(
function(){
animate(framesCount-1,(statesCount%3)+1);
},
statesCountSplit
);
}
}
animate(360*3,1);
I see a lot of:
var something = (is_something_true()) ? 3 : 4;
in javascript. Is this faster than
var something;
if (is_something_true()) {
something = 3;
} else {
something = 4;
}
Or is it written concisely for convenience?
Please enjoy this -- if difference is statistically valid then the result (true or false) also matters -- clearly this is just other stuff on the machine having an impact on browser performance:
Here is the link
There is a fundamental difference between the two, the ternary statements are expressions and not flow of control. If there is a case where someone writes it as a ternary expression instead of a standard if / than / else, when both would work the same they are (in my opinion) making the code harder to read without good reason.
In terms of speed there should be no difference. Unless you are using a really bad javascript implementation. The slowest part of both statements is the branching.
You should write for readability first and tiny micro-optimizations one-hundred and fifty-second. The first form is easier to read in many cases and there probably isn't much of a difference in performance one way or the other.
(Even if you disagree and think the second form is easier to read, asking about the relative performance difference is still the wrong question.)
Here is the statisitics:
After multiple tests and observations, it can be concluded,that the most cases the ternary operator(?:) is slower,than if/else.
Yes, there is negligible difference between the two.
However the difference is so small that it doesn't matter which one you use (I prefer if/else) because they help in readability which would save you a lot of time if someone is going through your code or maybe you yourself are maybe after say 3 months or so.
For those people who want to check the difference try this code:
// declarations
var num1 = 10, num2, i = 0, startTime, endTime, x, y;
// start timer
startTime = Math.floor((new Date()).getTime());
for(; i < 1e8; i++) {
// first part if /else
if(x == 10)
y = x;
else
y = 0;
// second part ternary
y = (x == 10) ? x : 0;
}
// end timer
endTime = Math.floor((new Date()).getTime() - startTime);
document.write("Time taken " + endTime + " ms");
Note: Comment one of the part and execute the code and run the loop for large number of iterations (above code millions of iterations).
Tip: Try running the loop multiple times to get average.
I've been doing great with my JS self-training. I'm stoked since I finally learned functions, and, or, calling functions, etc. I'm even excited because I sorted everything by user editable variables, non user variables, and created functions for everything else. So I have a question I'm trying to figure out. I am adding error codes to all my editable variables. My reasoning is that I know I won't always be in this position, job, life, etc, so I want to make sure that if someone new comes along, they will be able to edit and go. If they put alskjdfl where a 1, 2 or 3 should go, I'd like to return an error. I'm nerding out and adding my own error numbers for fun. Then if the user is smart enough they can view source on the JS code and see my notes as to why the error is displaying. Oh by the way, this is all internal documents, so I'm not worried about the web.
Below is the code. Basically, if I go to the variable and put in an alphabet character or some characters alsdfjlkjsdaf, it will break the page. I'm trying to find a way that says, if there is something in there beside 1-3, then set the speed to 1 and give an error. My attempts at this have failed so far because no matter what I put in there, it still breaks the page once a character is listed. I thought the name of the function seemed appropriate. :)
This is for a scrolling bar. It displays text information as well as work related things and a clock. It's embedded within an iframe.
/* Start speedlimit code - This code ensures speed won't be faster than 3. */
function speedLimitSet()
{
if ((speedSet !== 1) && (speedSet !== 2) && (speedSet !== 3))
{
speedSet = 1
//error code 1003
alert("Error Code 1003 - speedSet - Please change speed to 3 or less. This pop up will continue to pop up otherwise. Speed limit is set to 3 or less.")
}
}
//end speedlimit code
Edit:
/* Quality check for turnOffcrawler. It has to be typed as "Yes" or "No" else will error. */
function crawlerSwitch()
{
if (turnOffcrawler == "No") /* Code for general message is included in here. It looks long but it is spaced out. */
{
width = "1000px";
speed = speedSet;
errorFlag1000 = "No";
}
else if (turnOffcrawler == "Yes")
{
width = "0px";
speed = 0;
errorFlag1000 = "No";
}
else
{
width = "1000px";
speed = speedSet
errorFlag1000 = "Yes"
importantMessageError = "Error Code 1000 - turnOffcrawler is not set correctly. Please check settings and/or refer to instructions.       Error Code 1000 - turnoffcrawler is not set correctly. Please check settings and/or refer to instructions."
}
}
//end quality check
Which then links to:
function marqueeInitCall()
{
marqueeInit({
uniqueid: 'mycrawler',
style: {
'padding': '0px',
'width': width, //change to 1000 for normal, change to 0 for off
'background': scrollerBackground, //#00008B is background of menu bar
'border': '0px solid black'
},
inc: speed, //speed - pixel increment for each iteration of this marquee's movement
mouse: mouse, //mouseover behavior ('pause' 'cursor driven' or false)
moveatleast: 1,
neutral: 150,
savedirection: true
});
}
A couple of problems with that code:
You're not declaring any arguments. I'm guessing speedSet was meant to be an argument to the function?
You're using !== which is correct if you know that what you're being passed is already a number, not a numeric string. If you don't know that, you want to parse it first.
I probably wouldn't check against all three values individually, but that might be a style thing.
It's not saving the resulting value anywhere (so maybe my #1 is wrong). If speedSet is a global variable and this function is just validating its value, I'd recommend not using global variables.
so:
/* Start speedlimit code - This code ensures speed won't be faster than 3. */
function speedLimitSet(speedSet)
{
speedSet = parseInt(speedSet, 10); // Now it's a number or `NaN`
if (isNaN(speedSet) || speedSet < 1 || speedSet > 3)
{
speedSet = 1;
//error code 1003
alert("Error Code 1003 - speedSet - Please change speed to 3 or less. This pop up will continue to pop up otherwise. Speed limit is set to 3 or less.")
}
// Save it somewhere appropriate here
}
//end speedlimit code
Other items of note:
Indenting your code makes a huge difference to readability. Note how I've indented the code above.
Although JavaScript has the horror that is automatic semicolon insertion, my humble advice is never rely on it, always put in all of the necessary semicolons. (You needed one after speedSet = 1.)
alert isn't a great way to deal with programming errors. Recommend throwing an exception and handling it at a higher level in the code.
You're free to do what you like with your function names, but the convention for setter functions is usually setXyz (e.g., setSpeedLimit rather than speedLimitSet).
Doing a bind for a previous link in a nav. If we're on the first position don't do the same thing for the previous link. I was doing a "!=" not equal to test, but realized it could be a ">" greater than.
Then I thought, is one faster?
if (numberToCheck != 0) {
//doSomething();
}
vs.
if (numberToCheck > 0) {
//doSomething();
}
Performance questions should be resolved via measurement, not speculation.
You can see for yourself here http://jsperf.com/inequality-vs-greater-than. The results of this test (on my computer) vary by browser. Some are faster with inequality. Some are faster with less than. You will likely find much bigger speed differences in other areas of your code.
If you want to test something slightly different than what I put in the test, just add your own test for comparison.
Do you mean like... absolute difference, or "meaningfully different"?
In any case, it would depend 100% on the underlying VM implementation. It might be faster to set a flag and have that flag be the first in an && (for short-circuiting), though, and have the numerical part second.
if (keepChecking && numberToCheck != 0) {
keepChecking == false;
// doSomething();
}
Again, VM-dependent, and I can't believe it'd matter a lot either way.
What about -
if (numberToCheck !== 0) {
//doSomething();
}
Actually, I doubt a human could notice the difference. Plus, each browser js engine might yield different results.
I made a test page at jsperf:
http://jsperf.com/different-from
In Chrome on my MacBook Pro, they are exactly the same.