Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Call server every 5 seconds - returns stack overflow error

Tags:

angularjs

I want to call a method on an interval of time. I am receiving stack overflow error. What am I doing wrong:

html:

<div ng-app="myApp" ng-controller="Ctrl">
    <span>{{calledServer}}</span>
</div>

js:

var app = angular.module('myApp', []);

app.controller("Ctrl", function($scope, repo, poollingFactory) {
    $scope.calledServer;
    $scope.calledServer = poollingFactory.callFnOnInterval(function() {return repo.callServer(5);});
});

app.factory("repo", function() {

    function callServer(id){
        return "call server with id " + id;   
    }

    return {
        callServer: callServer
    };
});

app.factory("poollingFactory", function($timeout) {

    var timeIntervalInSec = 5;

    function callFnOnInterval(fn, timeInterval) {

        $timeout(callFnOnInterval, 1000 * timeIntervalInSec);
        callFnOnInterval(fn, timeIntervalInSec);
    };

    return {
        callFnOnInterval: callFnOnInterval
    };
});

jsfiddle: http://jsfiddle.net/fq4vg/423/

like image 385
Mdb Avatar asked Mar 18 '14 12:03

Mdb


2 Answers

You have a recursive call that isn't checking for any precondition.

An annotated version of your function:

function callFnOnInterval(fn, timeInterval) {

  //Schedule a call to 'callFnOnInterval' to happen in one second
  // and return immediately
  $timeout(callFnOnInterval, 1000 * timeIntervalInSec);

  //Immediately make a call to 'callFnOnInterval' which will repeat
  // this process ad-infinitum
  callFnOnInterval(fn, timeIntervalInSec);

};

Because you keep pushing calls onto the stack recursively and never returning, it eventually runs out of space.

Since the $timeout service returns a promise, you can use that to schedule more work once it is complete.

Here is what your service should probably look like:

app.factory("poollingFactory", function ($timeout) {

   var timeIntervalInSec = 5;

   function callFnOnInterval(fn, timeInterval) {

       var promise = $timeout(fn, 1000 * timeIntervalInSec);

       return promise.then(function(){
           callFnOnInterval(fn, timeInterval);
       });
   };

   return {
       callFnOnInterval: callFnOnInterval
   };
});

And here is an example jsFiddle to demonstrate: http://jsfiddle.net/jwcarroll/cXX2S/

A few notes about your code above.

You are trying to set a scope property value to the return of your callFnOnInterval but that isn't going to work. First, it doesn't return anything. Second, because it is an asynchronous call, at best it could return a promise.

like image 54
Josh Avatar answered Oct 21 '22 21:10

Josh


Your timeout method is calling itself until he runs out of space.

If you want to do something every x seconds use the $interval method.

app.factory("poollingFactory", function($interval) {

var timeIntervalInSec = 5;

function callFnOnInterval(fn, timeInterval) {
    return $interval(fn, 1000 * timeIntervalInSec);        
};

return {
    callFnOnInterval: callFnOnInterval
};
});

by the way, to get the result of the method back into your scope property you have to change the call to:

 poollingFactory.callFnOnInterval(function() {return $scope.calledServer = repo.callServer(5);});
like image 4
Tim Avatar answered Oct 21 '22 21:10

Tim