Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 3a4b6b8

Browse files
PatrickJSpetebacondarwin
authored andcommitted
feat($timeout): pass additional arguments to the callback
Similar to how [`setTimeout`](mdn.io/setTimeout#Syntax) works, this commit allows users of `$timeout` to add additional parameters to the call, which will now be passed on to the callback function. Closes #10631
1 parent 41fdb3d commit 3a4b6b8

File tree

2 files changed

+61
-12
lines changed

2 files changed

+61
-12
lines changed

src/ng/timeout.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ function $TimeoutProvider() {
3232
* @param {number=} [delay=0] Delay in milliseconds.
3333
* @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
3434
* will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
35+
* @param {...*=} Pass additional parameters to the executed function.
3536
* @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
3637
* promise will be resolved with is the return value of the `fn` function.
3738
*
@@ -43,14 +44,15 @@ function $TimeoutProvider() {
4344
fn = noop;
4445
}
4546

46-
var skipApply = (isDefined(invokeApply) && !invokeApply),
47+
var args = sliceArgs(arguments, 3),
48+
skipApply = (isDefined(invokeApply) && !invokeApply),
4749
deferred = (skipApply ? $$q : $q).defer(),
4850
promise = deferred.promise,
4951
timeoutId;
5052

5153
timeoutId = $browser.defer(function() {
5254
try {
53-
deferred.resolve(fn());
55+
deferred.resolve(fn.apply(null, args));
5456
} catch (e) {
5557
deferred.reject(e);
5658
$exceptionHandler(e);

test/ng/timeoutSpec.js

+57-10
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,16 @@ describe('$timeout', function() {
2222
it('should call $apply after each callback is executed', inject(function($timeout, $rootScope) {
2323
var applySpy = spyOn($rootScope, '$apply').andCallThrough();
2424

25-
$timeout(function() {});
25+
$timeout(noop);
2626
expect(applySpy).not.toHaveBeenCalled();
2727

2828
$timeout.flush();
2929
expect(applySpy).toHaveBeenCalledOnce();
3030

3131
applySpy.reset();
3232

33-
$timeout(function() {});
34-
$timeout(function() {});
33+
$timeout(noop);
34+
$timeout(noop);
3535
$timeout.flush();
3636
expect(applySpy.callCount).toBe(2);
3737
}));
@@ -40,7 +40,7 @@ describe('$timeout', function() {
4040
it('should NOT call $apply if skipApply is set to true', inject(function($timeout, $rootScope) {
4141
var applySpy = spyOn($rootScope, '$apply').andCallThrough();
4242

43-
$timeout(function() {}, 12, false);
43+
$timeout(noop, 12, false);
4444
expect(applySpy).not.toHaveBeenCalled();
4545

4646
$timeout.flush();
@@ -89,8 +89,8 @@ describe('$timeout', function() {
8989
// $browser.defer.cancel is only called on cancel if the deferred object is still referenced
9090
var cancelSpy = spyOn($browser.defer, 'cancel').andCallThrough();
9191

92-
var promise1 = $timeout(function() {}, 0, false);
93-
var promise2 = $timeout(function() {}, 100, false);
92+
var promise1 = $timeout(noop, 0, false);
93+
var promise2 = $timeout(noop, 100, false);
9494
expect(cancelSpy).not.toHaveBeenCalled();
9595

9696
$timeout.flush(0);
@@ -104,7 +104,6 @@ describe('$timeout', function() {
104104
expect(cancelSpy).toHaveBeenCalled();
105105
}));
106106

107-
108107
it('should allow the `fn` parameter to be optional', inject(function($timeout, log) {
109108

110109
$timeout().then(function(value) { log('promise success: ' + value); }, log.fn('promise error'));
@@ -123,6 +122,35 @@ describe('$timeout', function() {
123122
expect(log).toEqual(['promise success: undefined']);
124123
}));
125124

125+
it('should pass the timeout arguments in the timeout callback',
126+
inject(function($timeout, $browser, log) {
127+
var task1 = jasmine.createSpy('Nappa'),
128+
task2 = jasmine.createSpy('Vegeta');
129+
130+
$timeout(task1, 9000, true, 'What does', 'the timeout', 'say about', 'its delay level');
131+
expect($browser.deferredFns.length).toBe(1);
132+
133+
$timeout(task2, 9001, false, 'It\'s', 'over', 9000);
134+
expect($browser.deferredFns.length).toBe(2);
135+
136+
$timeout(9000, false, 'What!', 9000).then(function(value) { log('There\'s no way that can be right! ' + value); }, log.fn('It can\'t!'));
137+
expect($browser.deferredFns.length).toBe(3);
138+
expect(log).toEqual([]);
139+
140+
$timeout.flush(0);
141+
expect(task1).not.toHaveBeenCalled();
142+
143+
$timeout.flush(9000);
144+
expect(task1).toHaveBeenCalledWith('What does', 'the timeout', 'say about', 'its delay level');
145+
146+
$timeout.flush(1);
147+
expect(task2).toHaveBeenCalledWith('It\'s', 'over', 9000);
148+
149+
$timeout.flush(9000);
150+
expect(log).toEqual(['There\'s no way that can be right! undefined']);
151+
152+
}));
153+
126154

127155
describe('exception handling', function() {
128156

@@ -133,7 +161,7 @@ describe('$timeout', function() {
133161

134162
it('should delegate exception to the $exceptionHandler service', inject(
135163
function($timeout, $exceptionHandler) {
136-
$timeout(function() {throw "Test Error";});
164+
$timeout(function() { throw "Test Error"; });
137165
expect($exceptionHandler.errors).toEqual([]);
138166

139167
$timeout.flush();
@@ -145,7 +173,7 @@ describe('$timeout', function() {
145173
function($timeout, $rootScope) {
146174
var applySpy = spyOn($rootScope, '$apply').andCallThrough();
147175

148-
$timeout(function() {throw "Test Error";});
176+
$timeout(function() { throw "Test Error"; });
149177
expect(applySpy).not.toHaveBeenCalled();
150178

151179
$timeout.flush();
@@ -164,6 +192,25 @@ describe('$timeout', function() {
164192
}));
165193

166194

195+
it('should pass the timeout arguments in the timeout callback even if an exception is thrown',
196+
inject(function($timeout, log) {
197+
var promise1 = $timeout(function(arg) { throw arg; }, 9000, true, 'Some Arguments');
198+
var promise2 = $timeout(function(arg1, args2) { throw arg1 + ' ' + args2; }, 9001, false, 'Are Meant', 'To Be Thrown');
199+
200+
promise1.then(log.fn('success'), function(reason) { log('error: ' + reason); });
201+
promise2.then(log.fn('success'), function(reason) { log('error: ' + reason); });
202+
203+
$timeout.flush(0);
204+
expect(log).toEqual('');
205+
206+
$timeout.flush(9000);
207+
expect(log).toEqual('error: Some Arguments');
208+
209+
$timeout.flush(1);
210+
expect(log).toEqual('error: Some Arguments; error: Are Meant To Be Thrown');
211+
}));
212+
213+
167214
it('should forget references to relevant deferred even when exception is thrown',
168215
inject(function($timeout, $browser) {
169216
// $browser.defer.cancel is only called on cancel if the deferred object is still referenced
@@ -242,7 +289,7 @@ describe('$timeout', function() {
242289
// $browser.defer.cancel is only called on cancel if the deferred object is still referenced
243290
var cancelSpy = spyOn($browser.defer, 'cancel').andCallThrough();
244291

245-
var promise = $timeout(function() {}, 0, false);
292+
var promise = $timeout(noop, 0, false);
246293

247294
expect(cancelSpy).not.toHaveBeenCalled();
248295
$timeout.cancel(promise);

0 commit comments

Comments
 (0)