diff --git a/src/ng/timeout.js b/src/ng/timeout.js index b62bd748597d..d1f03460638c 100644 --- a/src/ng/timeout.js +++ b/src/ng/timeout.js @@ -4,7 +4,8 @@ function $TimeoutProvider() { this.$get = ['$rootScope', '$browser', '$q', '$$q', '$exceptionHandler', function($rootScope, $browser, $q, $$q, $exceptionHandler) { - var deferreds = {}; + + var deferreds = {}; /** @@ -19,12 +20,16 @@ function $TimeoutProvider() { * The return value of registering a timeout function is a promise, which will be resolved when * the timeout is reached and the timeout function is executed. * + * Additionally, the wrapper function can also be used without a target 'fn' function in order + * to generate a delayed promise. + * * 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. * - * @param {function()} fn A function, whose execution should be delayed. + * @param {function()} fn A function, whose execution should be delayed. This argument is + * optional and can be skipped if required. * @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. @@ -32,7 +37,18 @@ function $TimeoutProvider() { * promise will be resolved with is the return value of the `fn` function. * */ - function timeout(fn, delay, invokeApply) { + function timeout() { + var fn, delay, invokeApply; + if (isFunction(arguments[0])) { + fn = arguments[0], + delay = arguments[1], + invokeApply = arguments[2]; + } else { + fn = noop, + delay = arguments[0], + invokeApply = false; + } + var skipApply = (isDefined(invokeApply) && !invokeApply), deferred = (skipApply ? $$q : $q).defer(), promise = deferred.promise, diff --git a/test/ng/timeoutSpec.js b/test/ng/timeoutSpec.js index ec5bd8d25b8b..8c2a7693eec1 100644 --- a/test/ng/timeoutSpec.js +++ b/test/ng/timeoutSpec.js @@ -48,6 +48,17 @@ describe('$timeout', function() { })); + it('should NOT call $apply if no callback function is used', inject(function($timeout, $rootScope) { + var applySpy = spyOn($rootScope, '$apply').andCallThrough(); + + $timeout().then(function() {}); + expect(applySpy).not.toHaveBeenCalled(); + + $timeout.flush(); + expect(applySpy).not.toHaveBeenCalled(); + })); + + it('should NOT call $evalAsync or $digest if invokeApply is set to false', inject(function($timeout, $rootScope) { var evalAsyncSpy = spyOn($rootScope, '$evalAsync').andCallThrough(); @@ -69,6 +80,10 @@ describe('$timeout', function() { $timeout(noop, 123); expect(defer.callCount).toEqual(1); expect(defer.mostRecentCall.args[1]).toEqual(123); + + $timeout(456); + expect(defer.callCount).toEqual(2); + expect(defer.mostRecentCall.args[1]).toEqual(456); })); @@ -81,6 +96,14 @@ describe('$timeout', function() { $timeout.flush(); expect(log).toEqual(['timeout', 'promise success: buba']); + + var promise = $timeout(); + + promise.then(function(value) { log('promise success'); }, log.fn('promise error')); + expect(log).toEqual(['timeout', 'promise success: buba']); + + $timeout.flush(); + expect(log).toEqual(['timeout', 'promise success: buba', 'promise success']); })); @@ -165,19 +188,24 @@ describe('$timeout', function() { var task1 = jasmine.createSpy('task1'), task2 = jasmine.createSpy('task2'), task3 = jasmine.createSpy('task3'), - promise1, promise3; + task4 = jasmine.createSpy('task4'), + promise1, promise3, promise4; promise1 = $timeout(task1); $timeout(task2); promise3 = $timeout(task3, 333); + promise4 = $timeout(333); + promise3.then(task4); - $timeout.cancel(promise3); $timeout.cancel(promise1); + $timeout.cancel(promise3); + $timeout.cancel(promise4); $timeout.flush(); expect(task1).not.toHaveBeenCalled(); expect(task2).toHaveBeenCalledOnce(); expect(task3).not.toHaveBeenCalled(); + expect(task4).not.toHaveBeenCalled(); }));