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

Commit 2b2df47

Browse files
committed
feat($browser.$defer.cancel): support canceling defered tasks
1 parent 120701b commit 2b2df47

File tree

3 files changed

+86
-11
lines changed

3 files changed

+86
-11
lines changed

src/Browser.js

+35-7
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ function Browser(window, document, body, XHR, $log) {
4040
rawDocument = document[0],
4141
location = window.location,
4242
setTimeout = window.setTimeout,
43+
clearTimeout = window.clearTimeout,
44+
pendingDeferIds = {},
4345
lastLocationUrl;
4446

4547
self.isMock = false;
@@ -163,15 +165,12 @@ function Browser(window, document, body, XHR, $log) {
163165
* @returns {function()} the added function
164166
*/
165167
self.addPollFn = function(fn) {
166-
if (!pollTimeout) startPoller(100, setTimeout);
168+
if (isUndefined(pollTimeout)) startPoller(100, setTimeout);
167169
pollFns.push(fn);
168170
return fn;
169171
};
170172

171173
/**
172-
* @name angular.service.$browser#startPoller
173-
* @methodOf angular.service.$browser
174-
*
175174
* @param {number} interval How often should browser call poll functions (ms)
176175
* @param {function()} setTimeout Reference to a real or fake `setTimeout` function.
177176
*
@@ -339,20 +338,49 @@ function Browser(window, document, body, XHR, $log) {
339338
* @methodOf angular.service.$browser
340339
* @param {function()} fn A function, who's execution should be defered.
341340
* @param {number=} [delay=0] of milliseconds to defer the function execution.
341+
* @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.
342342
*
343343
* @description
344344
* Executes a fn asynchroniously via `setTimeout(fn, delay)`.
345345
*
346346
* Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using
347-
* `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed via
348-
* `$browser.defer.flush()`.
347+
* `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed
348+
* via `$browser.defer.flush()`.
349349
*
350350
*/
351351
self.defer = function(fn, delay) {
352+
var timeoutId;
352353
outstandingRequestCount++;
353-
setTimeout(function() { completeOutstandingRequest(fn); }, delay || 0);
354+
timeoutId = setTimeout(function() {
355+
delete pendingDeferIds[timeoutId];
356+
completeOutstandingRequest(fn);
357+
}, delay || 0);
358+
pendingDeferIds[timeoutId] = true;
359+
return timeoutId;
354360
};
355361

362+
363+
/**
364+
* @workInProgress
365+
* @ngdoc method
366+
* @name angular.service.$browser.defer#cancel
367+
* @methodOf angular.service.$browser.defer
368+
* @returns {boolean} Returns `true` if the task hasn't executed yet and was successfuly canceled.
369+
*
370+
* @description
371+
* Cancels a defered task identified with `deferId`.
372+
*/
373+
374+
self.defer.cancel = function(deferId) {
375+
if (pendingDeferIds[deferId]) {
376+
delete pendingDeferIds[deferId];
377+
clearTimeout(deferId);
378+
completeOutstandingRequest(noop);
379+
return true;
380+
}
381+
};
382+
383+
356384
//////////////////////////////////////////////////////////////
357385
// Misc API
358386
//////////////////////////////////////////////////////////////

src/angular-mocks.js

+18-1
Original file line numberDiff line numberDiff line change
@@ -281,15 +281,32 @@ function MockBrowser() {
281281
self.cookieHash = {};
282282
self.lastCookieHash = {};
283283
self.deferredFns = [];
284+
self.deferredNextId = 0;
284285

285286
self.defer = function(fn, delay) {
286287
delay = delay || 0;
287-
self.deferredFns.push({time:(self.defer.now + delay), fn:fn});
288+
self.deferredFns.push({time:(self.defer.now + delay), fn:fn, id: self.deferredNextId});
288289
self.deferredFns.sort(function(a,b){ return a.time - b.time;});
290+
return self.deferredNextId++;
289291
};
290292

293+
291294
self.defer.now = 0;
292295

296+
297+
self.defer.cancel = function(deferId) {
298+
var fnIndex;
299+
300+
forEach(self.deferredFns, function(fn, index) {
301+
if (fn.id === deferId) fnIndex = index;
302+
});
303+
304+
if (fnIndex) {
305+
self.deferredFns.splice(fnIndex, 1);
306+
}
307+
}
308+
309+
293310
self.defer.flush = function(delay) {
294311
if (angular.isDefined(delay)) {
295312
self.defer.now += delay;

test/BrowserSpecs.js

+33-3
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@ describe('browser', function(){
55
var browser, fakeWindow, xhr, logs, scripts, removedScripts, setTimeoutQueue;
66

77
function fakeSetTimeout(fn) {
8-
setTimeoutQueue.push(fn);
9-
return Math.random();
8+
return setTimeoutQueue.push(fn) - 1; //return position in the queue
9+
}
10+
11+
function fakeClearTimeout(deferId) {
12+
setTimeoutQueue[deferId] = noop; //replace fn with noop to preserve other deferId indexes
1013
}
1114

1215
fakeSetTimeout.flush = function() {
@@ -25,7 +28,8 @@ describe('browser', function(){
2528
xhr = null;
2629
fakeWindow = {
2730
location: {href:"http://server"},
28-
setTimeout: fakeSetTimeout
31+
setTimeout: fakeSetTimeout,
32+
clearTimeout: fakeClearTimeout
2933
};
3034

3135
var fakeBody = [{appendChild: function(node){scripts.push(node);},
@@ -161,6 +165,32 @@ describe('browser', function(){
161165
fakeSetTimeout.flush();
162166
expect(callback).toHaveBeenCalled();
163167
});
168+
169+
170+
it('should return unique deferId', function() {
171+
var deferId1 = browser.defer(noop),
172+
deferId2 = browser.defer(noop);
173+
174+
expect(deferId1).toBeDefined();
175+
expect(deferId2).toBeDefined();
176+
expect(deferId1).not.toEqual(deferId2);
177+
})
178+
179+
180+
describe('cancel', function() {
181+
it('should allow tasks to be canceled with returned deferId', function() {
182+
var log = [],
183+
deferId1 = browser.defer(function() { log.push('cancel me') }),
184+
deferId2 = browser.defer(function() { log.push('ok') }),
185+
deferId3 = browser.defer(function() { log.push('cancel me, now!') });
186+
187+
expect(log).toEqual([]);
188+
browser.defer.cancel(deferId1);
189+
browser.defer.cancel(deferId3);
190+
fakeSetTimeout.flush();
191+
expect(log).toEqual(['ok']);
192+
});
193+
});
164194
});
165195

166196

0 commit comments

Comments
 (0)