Sleep function in javascript - without using recursion - javascript

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/

Related

Javascript loop vs C loop for complex array

I am running some complex loop in node.js. But there is a problem I am facing. The time it takes for the loop to complete is around 200-300 ms which is very high. Will it be efficient if I convert also this piece of code to C? Or is there a better way? I have tried using clustering, fork(), reverse loops but nothing seems to make much difference
Some sample data
containers //Multidimensional 2D array on each index has array of 8 elements something like [ [1,2,3,4,5,6,7,8] ... ]
deleteItems= [1,2,3]
for (let indexi = 0; indexi < containers.length; indexi++) {
var shuoldRemove = false;
for (let indexj = 0; indexj < containers[indexi].length; indexj++)
{
for (let indexOfIPCPR = 0; indexOfIPCPR < deleteItems.length; indexOfIPCPR++){
if (containers[indexi][indexj] == deleteItems[indexOfIPCPR]){
shouldRemove = true;
shouldRemove && indexOfNextRound.splice(indexOfNextRound.indexOf(indexi),1);
}
}
}
}
The above code is further inside another loop. Which is much more worse.
Any help would be appreciated.
Thanks in advance
I think for very complex arrays you can get better speed by caching the array length. I see that you are getting the length in every iteration. This is how the loop should be updated to reduce the time taken in calculating array lengths. Please remember that modern JS engines do such optimization on their own. So, this may change nothing.
for (let indexi = 0, maxi = containers.length; indexi < maxi; indexi++) {
var shuoldRemove = false;
for (let indexj = 0, maxj = containers[indexi].length; indexj < maxj; indexj++)
{
for (let indexOfIPCPR = 0, maxDelete = deleteItems.length; indexOfIPCPR < maxDelete; indexOfIPCPR++){
if (containers[indexi][indexj] == deleteItems[indexOfIPCPR]){
shouldRemove = true;
shouldRemove && indexOfNextRound.splice(indexOfNextRound.indexOf(indexi),1);
}
}
}
}
As mentioned in the comments, this is not that simple and mainly depends on the content of your loop. But few relevant points that maybe will help you do decide:
The event-loop of Node.js is single threaded. It doesn't mean that everything will run in one thread - I/O (network operations, writing to files, etc) operations have their own threads and they will run async. BUT, if your code doesn't have lots of I/O, it will pretty much run in a single thread.
In C, you can create threads as you wish and run your code concurrently. But it will be more efficient only if your code can run concurrently, without the possibly high overhead of communicating between the threads, syncing them. So, if you can split the resources and the input data to few independent groups and then pass each group to a thread and run them all concurrently, that will probably will be more efficient then run it all in a single thread.
These will be the main differences between running it in Node.js and C - threads-wise. Of course, there are more aspects that differ between Node.js and C.

Why are higher order functions preferred over for-loops for iteration? [duplicate]

It seems that functional iterators are replacing the use of for loops in JS.
What is the advantage of passing a function such as map or reduce compared to a for/while loop?
var numbers = [1, 4, 9];
var doubles = numbers.map(function(num) {
return num * 2;
});
var doubles = [];
for (i = 0; i < numbers.length; i++) {
doubles[i] = numbers[i] * 2;
}
I have no idea why you would call the use of map a "closure". Closures are something else entirely. map is a higher-order function--defined as a function which operates on (takes or returns) a function. This style of programming can loosely be called "functional".
There are advantages and disadvantages to using functions like map. As one commenter pointed out, it's more compact:
function sum(array) {
var sum = 0;
for (var i = 0; i < array.length; i++) sum += array[i];
return sum;
}
vs.
function sum(array) {
return array.reduce(add);
}
Where add is function add(a, b) { return a + b; }.
More compact means more readable and less surface area for bugs. The use of the function named add also enhances readability; we can easily intuit that the operation is to add the elements of the array.
Basically, all the array functions have for-loop equivalents which require setting up more variables and writing more logic. For instance, map is
function map(array, fn) {
var result = [];
for (var i = 0; i < array.length; i++) result.push(fn(array[i]));
return result;
}
This can be written (much) more compactly as array.map(fn).
In many cases, we might already have functions defined which do the element mapping, or element filtering we want to do. In that case, we can simply use the functions as is with map, reduce etc.
map and its friends also have the advantage that they are friendly to sparse arrays. For instance:
var a = [];
a[1000000] = 1;
Now we double each element:
function double(array) {
var result = [];
for (var i = 0; i < array.length; i++) result.push(array[i] * 2);
return result;
}
This loops one million times and returns an array filled with NaNs. In contrast
array.map(elt => elt*2)
operates only on the single element which is present at position 1000000 and returns a sparse array as one would like.
The functional style also opens up additional possibilities for flexibility. Let's say we want to generalize the idea of multiplying things. I can write a higher-order function to create a function which multiplies some value by a particular factor:
function multiply(n) {
return function(x) {
return n * x;
};
}
Now I can write
array.map(multiply(2))
This level of conciseness and expressiveness is going to be hard to achieve in a for-loop solution.
forEach and map etc. are likely to be slower than a for loop. This could be an issue if your code is running a million times in a tight loop. In the real world, it rarely is an issue. It is better to prioritize code readability and compactness.
However, no one is forcing you to use map or filter. In ES7 or whatever it will be called, you will be able to use array comprehensions to accomplish the same thing in even more readable fashion:
[ for (i of array) if (i % 2) i + 1 ]
which combines a filter and a map.
A bit further afield, if you are planning to write a generator which iterates over an array, and yield some calculation from each element, you are going to need to use a for loop, since there is no way to yield from within a forEach callback:
function *double(array) {
for (var i = 0; i < array.length; i++) yield array[i]*2;
}
function *double(array) {
array.forEach(elt => yield elt*2); // DOESN'T WORK!!
}
It's a paradigm shift. The latter is a form of imperative programming, where the user is the one creating data that the computer consumes. The former is essentially a more functional based approach stemming from mathematics, utilizing data (code) that already exists.
There is no theoretical (processing) advantage of one over the other, though applied to the current state of computers, functional programming becomes more useful as processing power becomes greater.
Functional programming allows a form of reasoning based in mathematics emphasizing inputs and outputs. JavaScript in particular is good at handling this style due to functions being first-class data types
good answers here already. will just add one thing i came to appreciate with time: when you do things the "imperative"/old way it tends to encourage a style of programming with a lot of intermediate variables, mutable things all over and also the "while i'm iterating i might as well do this other thing on the same data" which is the biggest trap in code design - sacrificing separation of concerns for dubious performance gains. Consider this example
const numbers = [1,4,9,16];
let sum = 0;
let onlyEvenNumbers = [];
for(i = 0; i < numbers.length; i++) {
sum += numbers[i];
if(numbers[i] % 2 == 0) {
onlyEvenNumbers.push(numbers[i]);
}
}
this is bad imo cause you're gaining very little (if any) performance and the for loop doesn't have a clear single purpose. of course in this simple case it's probably ok, but it can get real ugly real fast. also it's not clear at first glance what gets stored in the onlyEvenNumbers var until you read to the bottom of the for loop - again, probably ok here, but if the for loop gets big it may get confusing.
functional approach for the win (also notice things can be not only const, but are even not mutated once constructed):
const numbers = [1,4,9,16];
const sum = numbers.reduce((acc, val) => acc + val);
const onlyEvenNumbers = numbers.filter(num => num % 2 == 0);

Measure what part of a loop that is slow?

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.

Javascript: TypeError variable is undefined

I am currently building a small web application with similar functionality across all modules. I want to code small generic functions so that all programmers next to me, call these functions and these functions return necessary but important data for them to implement their functionality. In this example, I am trying to deal with the typical "choose true or false" exercise. So from the template.php they call this function:
function checkAnswers(){
var radiobuttons = document.form1.exer1;
var correctAnswers = answers(); //this is an array of string
var checkedAnswers = checkExerciseRB(radiobuttons, 2, correctAnswers);
for(i=0; i<checkedAnswers.length; i++){
alert(checkedAnswers[i]);
}
}
Function checkExerciseRB is my generic function, it is called from checkAnswers.
function checkExerciseRB(rbuttons, opciones, correct){
var answers = new Array();
var control = 0;
for(i=0; i<rbuttons.length; i++){
var noPick="true";
for(j=0; j<opciones; j++){
if(rbuttons[control+j].checked){
if(rbuttons[control+j].value==correct[i]){
answers[i]= 1;
noPick="false";
break;
}
else{
answers[i]=2;
noPick="false";
break;
}
}
}
if(noPick=="true")
answers[i]=0;
control=control+opciones;
}
return answers;
}
It works great but while looking at my favorite browsers (FireFox, Chrome) error log it says:
TypeError: rbuttons[control + j] is undefined
Any clue on how to deal with this matter?
This probably means that control + j is greater than or equal to the length of the array rbuttons. There's no such array element as rbuttons[control + j].
You should learn how to use the JavaScript debugger in your favorite browsers! Debuggers are great. They let you watch this code run, line by line, as fast or as slow as you want, and watch how the value of control changes as you go.
You’ll watch it, and you’ll think “Oh! That line of code is wrong!”
You're looping through rbuttons.length times, but in each loop you're adding 2 to control. Using control to index your array, you're going to run past the end.
Does the index specified by control + j exist in the array? i.e: If that evaluates to 4, is there at least 5 items in the array?
Also, you should be using var i, var j, etc inside your for loop. Without it your variables are leaking into the scope this code is executed in (most likely the global scope, and that's not good) :)

Replacing repetitively occuring loops with eval in Javascript - good or bad?

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]);
});

Categories

Resources