This is relevant, b.c. I want to test looping structures. What I normally do is put in a simple statement like
i++
in the loop. I do this b.c. I wonder if a smart interpreter will not run empty blocks. For example.
for(var i = 0; i < 10; i++) {
}
might not loop at all as there is nothing in the loop.
so I normally do something like:
for(var i = 0; i < 10; i++) {
i++;
}
But this does test the i++ statement as well as the loop structure, which I don't want.
Here look at this. Notice the delay when trying to show the alert: http://jsfiddle.net/xs724/
for(var ii = 0; ii < 1000000000; ii++){}
alert("DONE");
I tested this in chrome. It most likely could vary from browser to browser.
JsPerf Link: http://jsperf.com/js-optimizationlooping
The answer is: You never know. There are lots of optimizations going on in modern JavaScript engines. One example is dead code elimination, which skips code that does not influence the end result.
There was a quite interesting controversy about this feature in IE9:
http://digitizor.com/2010/11/17/internet-explorer-9-caught-cheating-in-sunspider-benchmark/
But why would you want to run an empty block over and over anyway?
If you want the JavaScript interpreter to simply wait try this answers:
What is the JavaScript version of sleep()?
Sleep in Javascript - delay between actions
Related
Assuming that the while(true) will break at the same time as the for(...) loop, why is the for(...) faster?
According to jsbench, it is about 7% slower to use the while(true)
Here's the code I've used in the jsbench:
Using a while(true) loop
/* generate array */
const arr = []
for(let i = 0; i < 1000; i++){
arr.push(i)
}
let i = 0
while(true){
if(arr[i] >= 900){
return;
}
i++
}
using a for(...) loop:
/* generate array */
const arr = []
for(let i = 0; i < 1000; i++){
arr.push(i)
}
for(let i = 0; i < arr.length; i++){
if(arr[i] >= 900){
return;
}
}
The timing has to do with both your code and how JavaScript is compiled. The differences are pretty inconsequential in this example though, so testing which is faster varies each time the code is run and the results are pretty indeterministic. Generally, they should take about the same time or ever so slightly faster or slower.
Your code
Your while loop will continue simply because you have the condition set to always be true. You didn't include a condition to check if it should stop at any point after each iteration is complete.
Your for loop on the other hand has a condition that is checked every single time an iteration is complete (checking if i < arr.length still).
Other than that, your code is pretty much the same. They both have the same block of code, the difference is that the while loop increments i inside its code block, rather than like the for loop that increments i after its inner code block.
The differences in this case are pretty inconsequential.
Compilation
If you've ever studied some assembly code, you should be a little familiar with some of the structures for loops.
Depending on how the code is compiled determines which operations/instructions are run in what order. Also, the structure for a while loop should usually be different from a for loop in assembly, meaning that there may be an extra instruction to run in a for loop versus a while loop or vice versa depending on the programming language.
I've been trying to learn javascript by refactoring some Jquery examples in a book into javascript. In the following code I add a click listener to a tab and make it change to active when the user clicks on the tab.
var tabs = document.querySelectorAll(".tabs a span");
var content = document.querySelectorAll("main .content li");
for (var tabNumber = 0; tabNumber <= 2; tabNumber++) {
tabs[tabNumber].addEventListener("click", function (event) {
for (var i = 0; i < tabs.length; i++) {
tabs[i].classList.remove("active");
}
tabs[tabNumber].classList.add("active");
for (var i = 0; i < content.length; i++) {
content[i].innerHTML = "";
}
event.preventDefault();
});
}
This returns an undefined error when I run it. However, I tried replacing tabs[tabNumber].classList.add("active") with this.classList.add("active") and it worked.
Why doesn't the previous code work? As far as I can see they are referring to the same thing, and tabs[tabNumber] should work since at that point in the code it is tabs[0].
If use this, I think it's better and a more polished solution. If you still want to use tabNumber, it's probably evaluating to 3 in every click callback, because it's the number after the last iteration, and you don't have a tabs[3] position.
So, you just have to make a closure of the tabNumber variable.
I guess other answers told you why tabs[tabNumber] does not work (because it comes from the score of the for loop and so, is always equal to the greater value of tabNumber).
That's why I would recommend using a .forEach loop. Careful though because it doesn't work on arrays of DOM nodes produced by document.querySelectorAll(), but you can use:
// ES6
Array.from(document.querySelectorAll('...'))
// ES5
[].slice.call(document.querySelectorAll('...'))
Anyway, I made a simplified working demo of your code.
Note that I save the currently active tab in a variable, to prevent another for loop. You could also do:
document.querySelector('.active').classList.remove('active')
But I like to reduce the amount of DOM reading.
Good luck for your apprentissage, re-writing some jQuery code into Vanilla JS seems like a good method, and you might acquire a far better comprehension of JavaScript.
I'm looping through a dataset with a couple of thousand items in it like this.
users.forEach(function(user){
//List ALLTHETHINGS!
listAllEverything(user)
//Add gropings
user.groupings = groupings.filter(function(grouping){
return grouping.conditional(user)
})
//Add conversions to user, one per user.
user.conversions = {}
//for each conversionList
conversionLists.forEach(function(conversionList){
user.conversions[conversionList.name] = [];
//for each conversion
for (var i = conversionList.conversions.length - 1; i >= 0; i--) {
var conversion = conversionList.conversions[i]
//test against each users apilog
var converted = user.apilog.some(function(event){
return conversion.conditional(event);
})
if (converted){
//Lägg till konverteringen och alla konverteringar som kommer innan.
for (var i = i; i >= 0; i--){
user.conversions[conversionList.name].push(conversionList.conversions[i])
}
break;
}
};
})
})
I know this is not the most optimized code and I have some ideas how it can be improved. But i'm pretty new to these kinds of problems, so I'm not sure how I should prioritize. I know about console.time, which is useful but I want to use something that allows me to compound the time spent on each part of the forEach-loop, either a tool (I usually use chrome) or some debugging-method. Perferably something that doesn't effect the performance too much.
Since you are using Chrome you shoud check out the Timeline tab in your browsers DevTools - just hit the record button before running the loop and stop it once it's done. You will se a nice breakdown of everything that just happened and you will be mostly interested in yellow bars - they show JavaScript operations.
Please check out this video presentation by Paul Irish about Performance Tooling
As you know, in Chrome or Firefox you can just wrap a piece of code with console.time (and console.timeEnd) and it will measure the speed of particular operation and print it in the console.
For example: to measure the time it takes for an entire loop to execute use:
console.time('For loop benchmark');
for(i=0; i<1000; i++) {
// do some operations here
}
console.timeEnd('For loop benchmark');
But, if you want to measure each iteration you can parameterize the name of the log inside the loop so that you can name each specific operation the way you want:
for(i=0; i<1000; i++)
var consoleTimeName = 'Measuring iteration no '+i+' which is doing this and that...';
console.time(consoleTimeName);
// do some operations here
console.timeEnd(consoleTimeName);
}
Using it you can see for yourself how much faster simple for loop can be in comparsion to jQuery's $.each loop.
You can find more about this on developer.mozilla.org and developer.chrome.com. Please not that this is note a standarized, cross-browser compatibile feature and you should not be using it on a production website, since some browser like IE may throw you an error when they see it.
First of all, I've had a look on all the 'sleep' questions lying around (such as What is the JavaScript version of sleep()?) but I didn't find an acceptable solution.
I would like to make a visual education tool for all sort of algorithms. In order to do so, I'm using javascript with jQuery to display the data and paint it up nicely. In order to start it up, I want to do a sorting sample, where an array is displayed, shuffled and then sorted in a visually pleasing way. So what I want to happen is that two cells get highlighted (easy), possibly swapped (easy), and then there's a small delay before the next pair is tested (hard).
I understand there isn't an explicit 'sleep' method in javascript. However, to restructure the code into using setTimeout would imply rewriting all my algorithms recursively, which is a huge hinder (although obviously not impossible).
As a sample problem, take a look at a bubble sort sample:
function bubble_sort(arr){
for(var i=0;i<arr.length;i++){
for(var j=1;j<arr.length;j++){
highlight(j-1);
highlight(j);
if(arr[j-1] > arr[j]){
visible_swap(arr, j, j-1);
}
sleep(1000);
}
}
exhibit_array(arr);
}
This can obviously rewritten recursively to work with setTimeout, but to do so on all the algorithms I have in mind would take a great deal of time. Am I missing something? Is there an 'easy' way to leave the implementations as they are and place sleeps at will?
EDIT:
I found two solutions: a pretty one, and a compatible one.
The pretty one only works on firefox, I'm afraid, and makes use of the wonderful yield semantics (There is some sample explanation here: https://developer.mozilla.org/en/New_in_JavaScript_1.7). This actually solves my problem perfectly, thus:
function bubble_sort(arr){
for(var i=0;i<arr.length;i++){
for(var j=1;j<arr.length;j++){
highlight(j-1);
highlight(j);
if(arr[j-1] > arr[j]){
visible_swap(arr, j, j-1);
}
yield true;
}
}
yield false;
}
var bubble = bubble_sort(arr)
function gen(){
if(bubble.next()){
setTimeout(gen, 500);
}
else{
alert("Done!");
}
}
This works wonderfully for me, but does rely on the yield capability which currently is only supported on firefox. Notice that for this to work at all, you need to use <script type="text/javascript;version=1.7">. This however is perfect. It could have also worked for infinite algorithms, showing them toiling in vain if need be.
The second solution I found works as well, based on the answer below:
function bubble_sort(arr){
var q = new Array();
for(var i=0;i<arr.length;i++){
for(var j=1;j<arr.length;j++){
q[q.length] = [ [highlight, j-1 ], [highlight, j] ];
if(arr[j-1] > arr[j]){
swap(arr, j, j-1);
q[q.length] = [ [visible_swap, j, j-1] ];
}
}
}
return q;
}
function play(q, step){
if(q.length == 0)
return;
clear_highlights();
cmds = q.shift();
for(ind in cmds){
cmd = cmds[ind];
f = cmd.shift();
f.apply(null, cmd);
}
setTimeout(function(){ play(q, step); }, step);
}
This works as well. This is pretty bothersome syntactically, but definitely works well on all browsers.
After all this though, it seems there are javascript 'extensions' which implement sleep-like syntax, which is obviously better than all of the above.
Thanks for the help!
Recently I made a visualization of sub-palindrome finder algorithm, it used setTimeout and didn't require rewriting of the algorithm in recursive form.
See this example.
The general principle is to build up a stack of commands, for bubble sort that would be a stack of highlight and swap commands. Then you can have a function running each N milliseconds which takes a command from the stack and visualizes it.
commands = [
['highlight', 1, 5]
['swap', 1, 5]
['highlight', 3, 7]
...
];
setInterval(function() {
var cmd = commands.shift();
visualize(cmd);
}, 1300);
In my problem the finder algorithm was written in Python and was provided by the user, and I couldn't modify it. Fortunately Python allows to overload access and comparison operators and record each action the algorithm takes. RecString class. In JavaScript you can't do that, but that's not a problem in your case, because you can modify the original algorithm.
I can email you the JS source if you want, it was written in haste, but might be useful anyway.
Another idea - StratifiedJS. Here's a simple jsFiddle example:
<script src="http://code.onilabs.com/apollo/0.13/oni-apollo.js"></script>
<script type="text/sjs">
for (var i = 1; i < 4; i++) {
alert(i);
hold(1000);
}
</script>
I would work with setTimeout, I believe that is the closest you are going to get to a "sleep" equivalent on the client-side.
This answer doesn't solve the general case, but perhaps you can increment the interval for each instruction so that they run one second after each other.
function bubble_sort(arr){
var interval = 0; // increases with each loop
for(var i=0;i<arr.length;i++){
for(var j=1;j<arr.length;j++){
(function(i, j) {
setTimeout(function() {
highlight(j-1);
highlight(j);
if(arr[j-1] > arr[j]){
visible_swap(arr, j, j-1);
}
}, interval);
})(i, j);
interval += 1000;
}
}
exhibit_array(arr);
}
Thus, the first operation runs at once, the next runs after one second, the thrid after a total of two seconds, etc.
This solution provides the benefit of minimal code rewriting: just wrap your loop contents in a setTimeout (which is wrapped inside a closure with your loop variables) and add a line to increment interval after each loop iteration.
Using setTimeout() is not recursion.
You can work with a closure to keep track of state. The for loops, however, have to be changed into while for this to work:
function bubbleSort(arr) {
(function(i, j) { // <- this closes over i and j
function nextSortStep() {
while (i < arr.length) {
while (j < arr.length) {
highlight(j - 1);
highlight(j);
if (arr[j - 1] > arr[j]) {
visibleSwap(arr, j, j - 1);
}
j++;
return setTimeout(nextSortStep, 1000);
}
i++;
j = 1;
return setTimeout(nextSortStep, 1000);
}
exhibitArray(arr);
}
nextSortStep();
})(0, 1); // <- loop initialization
}
As an aside, JavaScript is not PHP, function names generally are in camelCase.
Following Lebedev's idea, I would store the "evolution of the sorting of the array" and then use setInterval() to show them.
http://jsfiddle.net/mari/EaYRZ/
I have a certain loop occurring several times in various functions in my code.
To illustrate with an example, it's pretty much along the lines of the following:
for (var i=0;i<= 5; i++) {
function1(function2(arr[i],i),$('div'+i));
$('span'+i).value = function3(arr[i]);
}
Where i is the loop counter of course. For the sake of reducing my code size and avoid repeating the loop declaration, I thought I should replace it with the following:
function loop(s) {
for (var i=0;i<= 5; i++) { eval(s); }
}
[...]
loop("function1(function2(arr[i],i),$('div'+i));$('span'+i).value = function3(arr[i]);");
Or should I? I've heard a lot about eval() slowing code execution and I'd like it to work as fast as a proper loop even in the Nintendo DSi browser, but I'd also like to cut down on code. What would you suggest?
Thank you in advance!
Why not just put the body of the loop into a function?
function doSomething(i, arr) {
function1(function2(arr[i],i), $('div'+i));
$('span'+i).value = function3(arr[i]);
}
and call it in the loop:
function loop() {
for (var i = 0; i <= 5; i++) { doSomething(i, arr); }
}
Gah!
This is a good question, but no, don't ever do that. Using eval in general is not recommended, as you won't see parse errors at load time, only at run time (harder to debug), it's harder to understand what's in scope when (harder to write), and you lose all your toolchain support (syntax highlight, script debugging).
Fortunately, since Javascript is basically a functional language, why not create a function that encapsulates what you want to do, and just call that?
function doMyThingNTimes(n, arr) {
for (var i=0;i <= n; i++) {
function1(function2(arr[i],i),$('div'+i));
$('span'+i).value = function3(arr[i]);
}
}
This is a dreadful idea.
It is inefficient
It is harder to debug
If you are concerned about bandwidth then use minification and HTTP compression.
Uh, no. eval should be treated as close to a last resort. JavaScript functions are First Class Objects so I would just declare whatever functions you need and pass them as one of the params.
Why not:
function loop(s) {
for (var i=0;i<= 5; i++) { s(i); }
}
loop(function4() {
function1(function2(arr[i],i),$('div'+i));$('span'+i).value = function3(arr[i]);
});