5

This is probably a total newb question...apologies, but I can't get my head around it.

In a lot of angular documentation/examples I see asynchronous functions wrapped in 'timeout' blocks. Many are wrapped in setTimeout() and require the explicit use of

if (!$scope.$$phase) {
    $scope.$apply();
}

Given that angular provides $timeout, the above code just seems outdated or wrong and within angular the use of $timeout should always be preferred. However, I digress.

Here is a snippet of some example code taken from: http://markdalgleish.com/2013/06/using-promises-in-angularjs-views/

var myModule = angular.module('myModule', []);
// From this point on, we'll attach everything to 'myModule'

myModule.factory('HelloWorld', function($timeout) {
  var getMessages = function(callback) {
    $timeout(function() {
      callback(['Hello', 'world!']);
    }, 2000);
  };

  return {
    getMessages: getMessages
  };
});

I see this wrapping of code in timeout blocks everywhere particularly related to asynchronous calls. But can someone explain why this is needed? Why not just change the code above to:

var myModule = angular.module('myModule', []);
// From this point on, we'll attach everything to 'myModule'

myModule.factory('HelloWorld', function() {
  var getMessages = function(callback) {
    callback(['Hello', 'world!']);
  };

  return {
    getMessages: getMessages
  };
});

Why wouldn't the code snippet above work just fine?

lostdorje
  • 6,150
  • 9
  • 44
  • 86
  • Because your code doesn't wait 2 seconds before returning? It executes the callback immediately. Are you asking why you need to use `$timeout` instead of `setTimeout`? Or are you asking why you need to use a timeout at all - because this is a standard way of "faking" an AJAX request. i.e. Wait 2 seconds and execute a callback – CodingIntrigue Mar 28 '14 at 09:38
  • I'm asking only about $timeout (setTimeout shouldn't be used in Angular as far as I can tell). Why do you need to use a timeout at all? And I'm not talking about faking it. Another good example of where you will see a timeout being used is in the nggrid documentation http://angular-ui.github.io/ng-grid/ . Scroll down to the Server-Side Paging Example and look in the JS tab. You'll see the use of a timeout there too, when indeed a real async call is being made. – lostdorje Mar 28 '14 at 09:58
  • Maybe you're totally right. All of these uses are just contrived examples to fake an asynch request and was just confusing me. I am using nggrid and per their example I use $timeout, but I am guessing the timeout can be removed entirely. – lostdorje Mar 28 '14 at 10:02
  • I see your point on that ng-grid page. It does seem to use a 100ms timeout for no reason at all! Even when an AJAX request is already taking place. But yes, timeouts are definitely not required! – CodingIntrigue Mar 28 '14 at 10:03
  • Hmmm, maybe there is a reason though...per the nggrid example even though they're using setTimeout (bad), assume they were using $timeout. There may be some small utility here. As far as I know if you end an async call without $scope.$apply() then angular will never know about the return value of the async event. However if you wrap your async call in $timeout(myAsyncCall, 1), with a minimal timeout value this will help ensure whatever got returned and possibly attached to the scope will actually get applied. This may be cleaner than calling $scope.$apply() yourself. Not sure though...shrug... – lostdorje Mar 28 '14 at 10:18
  • I suspect it could be this: http://stackoverflow.com/questions/779379/why-is-settimeoutfn-0-sometimes-useful – schmidlop Nov 26 '14 at 21:09
  • I'm confused as to what the question here is. You asked why this is necessary, stated that it seemed outdated, and then linked the usage from an article created in 2013, in which the code you show is specifically described as "a contrived example" to demonstrate how to do it the correct way, with promises. Are you asking for clarification of the article? because most of the points in the comments and answers so far have echoed what the article is suggesting. – Claies Nov 27 '15 at 20:42

2 Answers2

0

The use of $timeout or $interval is to implicitly trigger a digest cycle. The process is as follows:

  • Execute each task in the callback function
  • Call $apply after each task is executed
  • $apply triggers a digest cycle

An alternative is to inject $rootScope and call $rootScope.$digest() if you are using services that don't trigger a $digest cycle.

Angular uses a dirty-checking digest mechanism to monitor and update values of the scope during the processing of your application. The digest works by checking all the values that are being watched against their previous value and running any watch handlers that have been defined for those values that have changed.

This digest mechanism is triggered by calling $digest on a scope object. Normally you do not need to trigger a digest manually, because every external action that can trigger changes in your application, such as mouse events, timeouts or server responses, wrap the Angular application code in a block of code that will run $digest when the code completes.

References

Paul Sweatte
  • 24,148
  • 7
  • 127
  • 265
0

The $timeout in your example is probably used just to simulate an async function, like $http.get. As to why $timeout and not setTimeout: $timeout automatically tells angular to update the model, without the need to call $scope.$apply()

Also, consider the following example:

$scope.func = function(){
    $scope.showSomeLoadingThing = true;
    //Do some long-running stuff
    $scope.showSomeLoadingThing = false;
}

No loading thingy will be shown, you would have to write it like this:

$scope.func = function(){
    $scope.showSomeLoadingThing = true;
    $timeout(function(){
        //Do some long-running stuff
        $scope.showSomeLoadingThing = false;
    });
}
Arg0n
  • 8,283
  • 2
  • 21
  • 38