src/ng/timeout.js
'use strict';
var $timeoutMinErr = minErr('$timeout');
/** @this */
function $TimeoutProvider() {
this.$get = ['$rootScope', '$browser', '$q', '$$q', '$exceptionHandler',
function($rootScope, $browser, $q, $$q, $exceptionHandler) {
var deferreds = {};
/**
* @ngdoc service
* @name $timeout
*
* @description
* AngularJS's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch
* block and delegates any exceptions to
* {@link ng.$exceptionHandler $exceptionHandler} service.
*
* The return value of calling `$timeout` is a promise, which will be resolved when
* the delay has passed and the timeout function, if provided, is executed.
*
* To cancel a timeout request, call `$timeout.cancel(promise)`.
*
* In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
* synchronously flush the queue of deferred functions.
*
* If you only want a promise that will be resolved after some specified delay
* then you can call `$timeout` without the `fn` function.
*
* @param {function()=} fn A function, whose execution should be delayed.
* @param {number=} [delay=0] Delay in milliseconds.
* @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
* will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
* @param {...*=} Pass additional parameters to the executed function.
* @returns {Promise} Promise that will be resolved when the timeout is reached. The promise
* will be resolved with the return value of the `fn` function.
*
*/
function timeout(fn, delay, invokeApply) {
if (!isFunction(fn)) {
invokeApply = delay;
delay = fn;
fn = noop;
}
var args = sliceArgs(arguments, 3),
skipApply = (isDefined(invokeApply) && !invokeApply),
deferred = (skipApply ? $$q : $q).defer(),
promise = deferred.promise,
timeoutId;
timeoutId = $browser.defer(function() {
try {
deferred.resolve(fn.apply(null, args));
} catch (e) {
deferred.reject(e);
$exceptionHandler(e);
} finally {
delete deferreds[promise.$$timeoutId];
}
if (!skipApply) $rootScope.$apply();
}, delay, '$timeout');
promise.$$timeoutId = timeoutId;
deferreds[timeoutId] = deferred;
return promise;
}
/**
* @ngdoc method
* @name $timeout#cancel
*
* @description
* Cancels a task associated with the `promise`. As a result of this, the promise will be
* resolved with a rejection.
*
* @param {Promise=} promise Promise returned by the `$timeout` function.
* @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
* canceled.
*/
timeout.cancel = function(promise) {
if (!promise) return false;
if (!promise.hasOwnProperty('$$timeoutId')) {
throw $timeoutMinErr('badprom',
'`$timeout.cancel()` called with a promise that was not generated by `$timeout()`.');
}
if (!deferreds.hasOwnProperty(promise.$$timeoutId)) return false;
var id = promise.$$timeoutId;
var deferred = deferreds[id];
// Timeout cancels should not report an unhandled promise.
markQExceptionHandled(deferred.promise);
deferred.reject('canceled');
delete deferreds[id];
return $browser.defer.cancel(id);
};
return timeout;
}];
}