When to use $timeout

$timeout is the angular equivalent to settimeout in JavaScript. It is basically a wrapper aroung window.settimeout. So the basic functionality provided by $timeout is to have a piece of code executed asynchronously. As JavaScript doesn’t support thread spawning, asynchronously here means that the execution of the function is delayed.

Differences to settimeout

There are basically 2 differences between using $timeout and using directly settimeout:

  1. $timeout will by default execute a $apply on the root scope after the function is executed. This will cause a model dirty checking to be run.
  2. $timeout wraps the call of the provided function in a try/catch block and forwards any thrown exception to the global exception handler (the $exceptionHandler service).

Parameters

All parameters of $timeout are optional (although it of course doesn’t make much sense to call it without any parameters).

The first parameter is a function which execution is to be delayed.

The second parameter is a delay in milliseconds. You should now rely though on the delay to be absolutely respected. The minimum delay should be of 4 milliseconds in all modern browsers (you can set a smaller value but will probably not see a difference).

The third parameter is a flag (i.e. boolean, true or false) which when set to true, will cause $timeout not to execute $apply once the function is executed.

All additional parameters will be handled as parameters for the provided function and will be passed to the called function.

Delayed function execution

So two of the scenarios when you would want to use $timeout (or settimeout in this case) is:

either when you want to execute a function later on:

var executeInTenSeconds = function() {
    //Code executed 10 seconds later
};

$timeout(executeInTenSeconds, 10000);

or when you want to execute a function when the execution of the current block is finished:

var executeLater = function() {
    //Code executed once we're done with the current execution
};

$timeout(executeInTenSeconds);

Additional parameters

$timeout passes all parameters after the third one to the function being called. You can thus pass parameters to the function like this:

var executeInTenSeconds = function(increment) {
    $scope.myValue += increment;
};

$timeout(executeInTenSeconds, 10000, true, 10);

This will basically execute executeInTenSeconds(10); after 10 seconds, trigger the global exception manager in case of an unhandled exception and run a digest cycle afterwards.

Model dirty checking

A scenario where you’d rather use $timeout than settimeout is when you are modifying the model and need a digest cycle (dirty check) to run after the provided function is executed e.g.:

var executeInTenSeconds = function() {
    //Code executed 10 seconds later
	$scope.myScopeVar = "hello";
};

$timeout(executeInTenSeconds, 10000);

After 10 seconds our function will be called, it will change the value of a scope variable and after that a digest cycle will be triggered which will update the UI.

But there are cases when you actually do not need a model dirty checking (e.g. when you call the server but do not need to reflect the results of this call in you application). In such cases, you should use the third parameter of $timeout (invokeApply) e.g.:

var executeInTenSeconds = function() {
    //Code executed 10 seconds later and which doesn't require a digest cycle	
};

$timeout(executeInTenSeconds, 10000, false);

When the third parameter of $timeout is set to false, $timeout will skip the $rootScope.$apply() which is usually executed after the provided function.

Global exception handler

Since $timeout also wraps the provided function in a try/catch block and forwards all unhandled exceptions to the global exception handler, you may also use it in other cases too. I personally feel this is just a solution for lazy developers as you should rather wrap your function code in a try/catch block e.g.:

function($exceptionHandler) {
	try {
	  // Put here your function code
	} catch (e) {
	  // Put here some additional error handling call
	  $exceptionHandler(e); // Trigger the global exception handler
	}
	finally {
	  // Put here some cleanup logic
	}
}

And instead of duplicating this code everywhere you should probably consider writing your own reusable provider e.g.:

'use strict';

function $ExceptionWrapperProvider() {
  this.$get = ['$exceptionHandler', function($exceptionHandler) {

    function exceptionWrapper(fn) {
        try {
			return fn.apply(null, arguments);
        } catch (e) {
          $exceptionHandler(e);
        }
		return null;
    }

    return exceptionWrapper;
  }];
}

$timeout without function

All parameters of $timeout are optional, even the function. So why would you need to call $timeout without a function ? Basically, if you call $timeout without a function, there is no function execution, thus no exceptions and all that remains is the delay and the digest cycle. So calling $timeout without a function e.g.:

$timeout(10000);

Basically just triggers a digest cycle after the provided delay. In the example above, it would cause a digest cycle to be run after 10 seconds. But of course doing this is probably a sign that something’s wrong in your application (you should need to run delayed digest cycles but should rather run them after some logic has been executed). But if something is run asynchronously outside of your code but you do not get called back when it’s done and this external code somehow modifies something in the angular scopes, you might need to handle it this way. In this case, using $timeout is not really different from using:

settimeout( function() {
	$rootScope.$apply();
}, 10000);

It’s just less lines of code…

Leave a Reply

Your email address will not be published. Required fields are marked *