Web Analytics Made Easy -
StatCounter Recursive increment & setTimeout? - CodingForum

Announcement

Collapse
No announcement yet.

Recursive increment & setTimeout?

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Recursive increment & setTimeout?

    Why does my function run out of memory if I don't use setTimeout(..., 0)?

    I can see what's happening:

    if the loop number is greater than 459, the error occurs, and without a timeout, the output moves at light-speed.

    However, I don't understand what's actually going on here...

    why does the "out of memory" error occur, and what does a zero timeout-delay do to correct the problem?

    Code:
    <html>
    <head>
    <title>-</title>
    
    <script type="text/JavaScript">
    
    var i, n, stop;
    
    function Recurse(oForm){
    i++;
    oForm.progress.value = i;
    oForm.percentage.value = Math.floor(((i / n) * 100)) + "%";
    i < n && +stop != 1 ? [COLOR=red]setTimeout(function (){Recurse(oForm);}, 0)[/COLOR] : controlUpdate("Complete");
    }
    
    function controlUpdate(callString){
    oForm = document.RecTest;
    
    switch(callString){
    
    case "Start" : 
    n = new Number(oForm.test.value);
    if(isNaN(n) || n < 1){
    alert("loop value must be a number greater than 0. ");
    }
    else{
    i = 0;
    stop = false;
    oForm.cancel.disabled = 0;
    oForm.start.disabled = 1;
    oForm.test.disabled = 1;
    Recurse(oForm);
    }
    break;
    
    case "Cancel" : 
    stop = true;
    oForm.rs.disabled = 0;
    oForm.cancel.disabled = 1;
    break;
    
    case "Complete" : 
    oForm.rs.disabled = 0;
    break;
    
    case "Reset" : 
    oForm.cancel.disabled = 1;
    oForm.start.disabled = 0;
    oForm.test.disabled = 0;
    oForm.rs.disabled = 1;
    break;}
    }
    </script>
    
    <style type="text/css">
    form{
    text-align:center
    }
    input{
    text-align:center;vertical-align:middle
    }
    label{
    padding-left:10px;padding-right:5px
    }
    </style>
    
    </head>
    <body>
    
    <form name="RecTest" onreset="controlUpdate('Reset')">
    <label>i :</label><input name="progress" size="10" readonly>
    <label>% :</label><input name="percentage" size="10" readonly>
    <br><br>
    <label>loop :</label><input name="test" value="500" size="10" maxlength="5">
    <input name="start" type="button" value="Start" onclick="controlUpdate('Start')">
    <input name="cancel" type="button" value="Cancel" disabled onclick="controlUpdate('Cancel')">
    <input name="rs" type="reset" disabled>
    </form>
    
    </body>
    </html>
    Last edited by swmr; Feb 9, 2004, 02:16 AM.
    hmm... ?

  • #2
    liorean can explain this better but I might as well share that Javascript recursion has maximum depth. By using setTimeout or setInterval, you can make it an endless loop.
    Glenn
    vBulletin Mods That Rock!

    Comment


    • #3
      Yeah, that's interesting... I wonder what the difference is between maximum depth, or memory (or whatever), as it applies to the Function Object vs. the For/While Statements... and, why those statements won't show output results until they have finished looping.
      hmm... ?

      Comment


      • #4
        hi,
        what the javascript interpreter does if it detects true recursivnes, like you use it here, is pushing the function object on the execution stack each time it gets called.
        this is why the memory usage rises so rapidly and it stops when the interpreter needs more memory then it reserves itself. thats why the results vary for different browsers because there is no definition how much memory a javascript interpreter should use and each browser handles this differently.
        in some languages there is a technique called "tail call elimination", where the interpreter detects and removes unmodified objects from the stack, so that you can recurse endlessly but this is not covered in the ecma-scriüt spec and there exists only one javascript interpreter which can handle this (http://wiki.cocoondev.org/Wiki.jsp?p...hContinuations).
        so as long as you don't know how often you have to recurse or supply a mechanism to break out of the recursion, usage setTimeout() or
        setInterval() is better as it uses always the same function object but with the defined delay between the calls.

        Comment


        • #5
          Thank you for explaining that.
          hmm... ?

          Comment


          • #6
            There is one thing to it, though: A recursive function returns the results to the context. A function called from a setTimeout or setInterval doesn't. That may or may not limit the possibility of using setTimeout or setInterval for this kind of job. In general an iterative statement such as the do..while loop, the while loop or the for loop is the better choice.
            liorean <[[email protected]]>
            Articles: RegEx evolt wsabstract , Named Arguments
            Useful Threads: JavaScript Docs & Refs, FAQ - HTML & CSS Docs, FAQ - XML Doc & Refs
            Moz: JavaScript DOM Interfaces MSDN: JScript DHTML KDE: KJS KHTML Opera: Standards

            Comment


            • #7
              Thanks liorean, would you happen to have any code snippets that illustrate the difference there?

              From what I gather, recursion is the only way to update a control - such as a progress bar - for each incremental step... so it seems that's where it would be required.
              hmm... ?

              Comment


              • #8
                FWIW...
                Code:
                <html>
                <head>
                <title>-</title>
                
                <script type="text/JavaScript">
                
                var i, n, stop, [color=red]timer[/color];
                
                function Recurse(oForm){
                i++;
                oForm.progress.value = i;
                oForm.percentage.value = Math.floor(((i / n) * 100)) + "%";
                [color=red]if (i >= n || stop) controlUpdate("Complete");[/color]
                }
                
                function controlUpdate(callString){
                oForm = document.RecTest;
                
                switch(callString){
                
                case "Start" : 
                n = new Number(oForm.test.value);
                if(isNaN(n) || n < 1){
                alert("loop value must be a number greater than 0. ");
                }
                else{
                i = 0;
                stop = false;
                oForm.cancel.disabled = 0;
                oForm.start.disabled = 1;
                oForm.test.disabled = 1;
                [color=red]timer = setInterval(function(){Recurse(oForm)},1);[/color]
                }
                break;
                
                case "Cancel" : 
                [color=red]clearInterval(timer);[/color]
                stop = true;
                oForm.rs.disabled = 0;
                oForm.cancel.disabled = 1;
                break;
                
                case "Complete" : 
                [color=red]clearInterval(timer);[/color]
                oForm.rs.disabled = 0;
                break;
                
                case "Reset" : 
                oForm.cancel.disabled = 1;
                oForm.start.disabled = 0;
                oForm.test.disabled = 0;
                oForm.rs.disabled = 1;
                break;}
                }
                </script>
                
                <style type="text/css">
                form{
                text-align:center
                }
                input{
                text-align:center;vertical-align:middle
                }
                label{
                padding-left:10px;padding-right:5px
                }
                </style>
                
                </head>
                <body>
                
                <form name="RecTest" onreset="controlUpdate('Reset')">
                <label>i :</label><input name="progress" size="10" readonly>
                <label>% :</label><input name="percentage" size="10" readonly>
                <br><br>
                <label>loop :</label><input name="test" value="500" size="10" maxlength="5">
                <input name="start" type="button" value="Start" onclick="controlUpdate('Start')">
                <input name="cancel" type="button" value="Cancel" disabled onclick="controlUpdate('Cancel')">
                <input name="rs" type="reset" disabled>
                </form>
                
                </body>
                </html>
                Last edited by glenngv; Feb 9, 2004, 09:38 PM.
                Glenn
                vBulletin Mods That Rock!

                Comment


                • #9
                  stop = false; if(!stop)... -- that's good to know!


                  Thanks for the example, glenngv.

                  Is there an advantage to using setInterval instead of setTimeout, here, or was that just to demonstrate the alternative?
                  hmm... ?

                  Comment


                  • #10
                    If you want to call the function repetitively, then setInterval is better because you don't have to call the function again inside that function. But if you want to call the function only once with a delay, then use setTimeout.
                    Glenn
                    vBulletin Mods That Rock!

                    Comment


                    • #11
                      Ah, setInterval does sound more appropriate, but how can I know how long a function will take to execute: would there be a possibility of calling it again too soon?

                      Also, what happens differently when a function is called from within itself?
                      hmm... ?

                      Comment


                      • #12
                        setInterval will wait for the function to finish execution before executing the function again unless there is setTimeout inside in which the setInterval function is re-executed regardless the setTimeout function has finished execution or not. Hope that makes sense.

                        According to this test, setTimeout is faster than setInterval.
                        Glenn
                        vBulletin Mods That Rock!

                        Comment


                        • #13
                          Yeah, that made sense; thank you.
                          hmm... ?

                          Comment

                          Working...
                          X