Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sleep function in javascript - without using recursion

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!

like image 916
Gilthans Avatar asked Dec 01 '25 05:12

Gilthans


1 Answers

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.

like image 129
Alexey Lebedev Avatar answered Dec 03 '25 17:12

Alexey Lebedev



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!