Fix #1426 clearTimeout not correctly clearing a timeout
clearTimeout was not correctly handling the case of clearing a timeout that is also scheduled to run at the same tick. This fix adds a deletedKeys array that is checked whilst we are running the scheduled functions for the current clock tick. If a function exists in deletedKeys it will not be ran. deletedKeys is then reset to an empty array.
This commit is contained in:
@@ -680,7 +680,7 @@ describe("Clock (acceptance)", function() {
|
|||||||
expect(actualTimes).toEqual([baseTime.getTime(), baseTime.getTime() + 1, baseTime.getTime() + 3]);
|
expect(actualTimes).toEqual([baseTime.getTime(), baseTime.getTime() + 1, baseTime.getTime() + 3]);
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should be able to clear a timeout', function () {
|
it('correctly clears a scheduled timeout while the Clock is advancing', function () {
|
||||||
var delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
|
var delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
|
||||||
global = {Date: Date, setTimeout: undefined},
|
global = {Date: Date, setTimeout: undefined},
|
||||||
mockDate = new jasmineUnderTest.MockDate(global),
|
mockDate = new jasmineUnderTest.MockDate(global),
|
||||||
@@ -694,10 +694,26 @@ describe("Clock (acceptance)", function() {
|
|||||||
global.clearTimeout(timerId2);
|
global.clearTimeout(timerId2);
|
||||||
}, 100);
|
}, 100);
|
||||||
|
|
||||||
timerId2 = global.setTimeout(() => {
|
timerId2 = global.setTimeout(fail, 100);
|
||||||
fail();
|
|
||||||
}, 100);
|
|
||||||
|
|
||||||
clock.tick(100);
|
clock.tick(100);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('correctly clears a scheduled interval while the Clock is advancing', function () {
|
||||||
|
var delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
|
||||||
|
global = {Date: Date, setTimeout: undefined},
|
||||||
|
mockDate = new jasmineUnderTest.MockDate(global),
|
||||||
|
clock = new jasmineUnderTest.Clock(global, function () { return delayedFunctionScheduler; }, mockDate);
|
||||||
|
|
||||||
|
clock.install();
|
||||||
|
|
||||||
|
var timerId2;
|
||||||
|
var timerId1 = global.setInterval(function () {
|
||||||
|
global.clearInterval(timerId2);
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
timerId2 = global.setInterval(fail, 100);
|
||||||
|
|
||||||
|
clock.tick(400);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ getJasmineRequireObj().DelayedFunctionScheduler = function() {
|
|||||||
var scheduledFunctions = {};
|
var scheduledFunctions = {};
|
||||||
var currentTime = 0;
|
var currentTime = 0;
|
||||||
var delayedFnCount = 0;
|
var delayedFnCount = 0;
|
||||||
|
var deletedKeys = [];
|
||||||
|
|
||||||
self.tick = function(millis, tickDate) {
|
self.tick = function(millis, tickDate) {
|
||||||
millis = millis || 0;
|
millis = millis || 0;
|
||||||
@@ -51,6 +52,8 @@ getJasmineRequireObj().DelayedFunctionScheduler = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
self.removeFunctionWithId = function(timeoutKey) {
|
self.removeFunctionWithId = function(timeoutKey) {
|
||||||
|
deletedKeys.push(timeoutKey);
|
||||||
|
|
||||||
for (var runAtMillis in scheduledFunctions) {
|
for (var runAtMillis in scheduledFunctions) {
|
||||||
var funcs = scheduledFunctions[runAtMillis];
|
var funcs = scheduledFunctions[runAtMillis];
|
||||||
var i = indexOfFirstToPass(funcs, function (func) {
|
var i = indexOfFirstToPass(funcs, function (func) {
|
||||||
@@ -126,7 +129,10 @@ getJasmineRequireObj().DelayedFunctionScheduler = function() {
|
|||||||
|
|
||||||
currentTime = newCurrentTime;
|
currentTime = newCurrentTime;
|
||||||
|
|
||||||
var funcsToRun = scheduledFunctions[currentTime];
|
var funcsToRun = scheduledFunctions[currentTime].sort(function (a, b) {
|
||||||
|
return a.millis > b.millis;
|
||||||
|
});
|
||||||
|
|
||||||
delete scheduledFunctions[currentTime];
|
delete scheduledFunctions[currentTime];
|
||||||
|
|
||||||
forEachFunction(funcsToRun, function(funcToRun) {
|
forEachFunction(funcsToRun, function(funcToRun) {
|
||||||
@@ -136,8 +142,13 @@ getJasmineRequireObj().DelayedFunctionScheduler = function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
forEachFunction(funcsToRun, function(funcToRun) {
|
forEachFunction(funcsToRun, function(funcToRun) {
|
||||||
|
if (deletedKeys.indexOf(funcToRun.timeoutKey) !== -1) {
|
||||||
|
// skip a timeoutKey deleted whilst we were running
|
||||||
|
return;
|
||||||
|
}
|
||||||
funcToRun.funcToCall.apply(null, funcToRun.params || []);
|
funcToRun.funcToCall.apply(null, funcToRun.params || []);
|
||||||
});
|
});
|
||||||
|
deletedKeys = [];
|
||||||
} while (scheduledLookup.length > 0 &&
|
} while (scheduledLookup.length > 0 &&
|
||||||
// checking first if we're out of time prevents setTimeout(0)
|
// checking first if we're out of time prevents setTimeout(0)
|
||||||
// scheduled in a funcToRun from forcing an extra iteration
|
// scheduled in a funcToRun from forcing an extra iteration
|
||||||
|
|||||||
Reference in New Issue
Block a user