2

Please consider the following:

$(document).ready(function () {
    var promise;

    (function refresh(){
        promise = loadInfo();
        promise.done( function() {
            $.each(loadedData, function(key, value){
                $('#' + key + ' div.info').html(value.label);
            })
            // Call itself for next iteration
            window.setTimeout(refresh, 5 *1000);
        })
    })()
})
  • Do you think each iteration create a new var promise or they all reuse the same one?
  • In case a new var is created for each iteration, can I have an overload overtime (stack overflow!!!) ;) ? The application is displaying data and is supposed to run for long times
  • I also have another version with setInterval((function refresh(){...}), 5 *1000) without the setTimeout, which one is better? Thoughts?

Thank you

idris
  • 187
  • 2
  • 18
  • what you showed is not recursion in the classical sense, rather - chained calls with delay, therefore, stack overflow will not happen – Igor Sep 01 '15 at 16:14
  • @Igor since the refresh function calls itself, whether it's after a delay or not, it is still recursive. – Jonathan.Brink Sep 01 '15 at 16:18
  • 1
    @Jonathan.Brink - no, refresh function does not call itself – Igor Sep 01 '15 at 16:18
  • @Igor it's calling itself in this line: window.setTimeout(refresh, 5 *1000); – Jonathan.Brink Sep 01 '15 at 16:20
  • 2
    ^^ + `setTimeout` inside the loop is IMO preferable. Because, in case of long running indeterminate function call, `setInterval` may get overlap, whereas `setTimeout` will be called only when the call finishes and hence gives you a truer delay. – Abhitalks Sep 01 '15 at 16:21
  • @Jonathan.Brink - this is not a call of `refresh`, but I do not want to argue - let it be "recursion" – Igor Sep 01 '15 at 16:22
  • @Igor how is it not a call of refresh? Are you saying it's not recursive because a reference to refresh is passed to setTimeout so technically setTimeout is the callee? – Jonathan.Brink Sep 01 '15 at 16:24
  • @Jonathan.Brink - now we are getting somewhere – Igor Sep 01 '15 at 16:25
  • @Igor thanks, the distinction is clear now – Jonathan.Brink Sep 01 '15 at 16:30

3 Answers3

2

Since the promise variable is declared above the refresh function it is available via closure and will be re-used, so that shouldn't cause a stack overflow, but the implementation of loadInfo would determine if a new variable is created each time or not.

This might help shed some light on JavaScript and variable scoping: How do JavaScript closures work?

Perhaps a slightly cleaned up version could look like this:

$(document).ready(function () {
    (function refresh(){
        loadInfo().done( function(loadedData) {
            $.each(loadedData, function(key, value){
                $('#' + key + ' div.info').html(value.label);
            });
            // Call itself for next iteration
            window.setTimeout(refresh, 5 *1000);
        });
    })();
});

Using setInterval may be more readable to some eyes, but I think the setTimeout approach you have is fine.

Community
  • 1
  • 1
Jonathan.Brink
  • 23,757
  • 20
  • 73
  • 115
  • Nice! But a quick one: why pass loadedData as variable to the callback function? It's actually a global variable that is already available. – idris Sep 01 '15 at 17:04
  • There may well be a valid reason for you to keep that as a global variable. I was just thinking that if it's possible to avoid the global variable to do so. Feel free to leave that out though if it's not conducive to your logic flow. – Jonathan.Brink Sep 01 '15 at 17:07
1

setInterval ensure periodic request(but doesn't ensure response order) but setTimeout(your code) doesn't ensure this. If there is long time response, the waiting time is also deferred. Plus if your loadInfo() request fails, need more code for next request.

The decision is up to your server environment and your app's priority.( between performance and accurateness )

Refer to my setTimeout code, if it'll help.

$(document).ready(function () {

    // for api
    function repeatLoad( cb ) {

        var bindedRepeatLoad = repeatLoad.bind( this, cb );
        var repeat = setTimeout.bind( this, bindedRepeatLoad, 5*1000 );

        loadInfo()
        .done( cb )
        .done( repeat )
        .error( repeat );
    }

    // for view
    function render( loadedData ) {
        $.each(loadedData, function(key, value){
            $('#' + key + ' div.info').html(value.label);
        });
    }

    // for app logic, only 1 line is needed.
    repeatLoad( render );
});
ssohjiro
  • 72
  • 4
  • Great! I feel that I need to up my JS knowledge. Thank you! However I am accepting Jonathan.Brink's because it's more understandable for me. – idris Sep 01 '15 at 17:38
  • @zwan thanks, Ye, that's just my style code. I like bind function because it makes code little less but sometime bind functions make it hard at first sight. – ssohjiro Sep 02 '15 at 16:32
0

setTimeout in this current code will wait for the function to finish, then wait for the specified time and then calls the refresh function.

setInterval will keep calling the function after a given amount of time irrespective of whether the function has finished its execution or not

Puneet
  • 654
  • 1
  • 8
  • 16