You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
284 lines
10 KiB
284 lines
10 KiB
// Copyright (c) Microsoft, All rights reserved. See License.txt in the project root for license information. |
|
|
|
;(function (factory) { |
|
var objectTypes = { |
|
'function': true, |
|
'object': true |
|
}; |
|
|
|
function checkGlobal(value) { |
|
return (value && value.Object === Object) ? value : null; |
|
} |
|
|
|
var freeExports = (objectTypes[typeof exports] && exports && !exports.nodeType) ? exports : null; |
|
var freeModule = (objectTypes[typeof module] && module && !module.nodeType) ? module : null; |
|
var freeGlobal = checkGlobal(freeExports && freeModule && typeof global === 'object' && global); |
|
var freeSelf = checkGlobal(objectTypes[typeof self] && self); |
|
var freeWindow = checkGlobal(objectTypes[typeof window] && window); |
|
var moduleExports = (freeModule && freeModule.exports === freeExports) ? freeExports : null; |
|
var thisGlobal = checkGlobal(objectTypes[typeof this] && this); |
|
var root = freeGlobal || ((freeWindow !== (thisGlobal && thisGlobal.window)) && freeWindow) || freeSelf || thisGlobal || Function('return this')(); |
|
|
|
// Because of build optimizers |
|
if (typeof define === 'function' && define.amd) { |
|
define(['./rx'], function (Rx, exports) { |
|
return factory(root, exports, Rx); |
|
}); |
|
} else if (typeof module === 'object' && module && module.exports === freeExports) { |
|
module.exports = factory(root, module.exports, require('./rx')); |
|
} else { |
|
root.Rx = factory(root, {}, root.Rx); |
|
} |
|
}.call(this, function (root, exp, Rx, undefined) { |
|
|
|
// Aliases |
|
var Scheduler = Rx.Scheduler, |
|
ScheduledItem = Rx.internals.ScheduledItem, |
|
SchedulePeriodicRecursive = Rx.internals.SchedulePeriodicRecursive, |
|
PriorityQueue = Rx.internals.PriorityQueue, |
|
inherits = Rx.internals.inherits, |
|
defaultSubComparer = Rx.helpers.defaultSubComparer, |
|
notImplemented = Rx.helpers.notImplemented; |
|
|
|
/** Provides a set of extension methods for virtual time scheduling. */ |
|
var VirtualTimeScheduler = Rx.VirtualTimeScheduler = (function (__super__) { |
|
inherits(VirtualTimeScheduler, __super__); |
|
|
|
/** |
|
* Creates a new virtual time scheduler with the specified initial clock value and absolute time comparer. |
|
* |
|
* @constructor |
|
* @param {Number} initialClock Initial value for the clock. |
|
* @param {Function} comparer Comparer to determine causality of events based on absolute time. |
|
*/ |
|
function VirtualTimeScheduler(initialClock, comparer) { |
|
this.clock = initialClock; |
|
this.comparer = comparer; |
|
this.isEnabled = false; |
|
this.queue = new PriorityQueue(1024); |
|
__super__.call(this); |
|
} |
|
|
|
var VirtualTimeSchedulerPrototype = VirtualTimeScheduler.prototype; |
|
|
|
VirtualTimeSchedulerPrototype.now = function () { |
|
return this.toAbsoluteTime(this.clock); |
|
}; |
|
|
|
VirtualTimeSchedulerPrototype.schedule = function (state, action) { |
|
return this.scheduleAbsolute(state, this.clock, action); |
|
}; |
|
|
|
VirtualTimeSchedulerPrototype.scheduleFuture = function (state, dueTime, action) { |
|
var dt = dueTime instanceof Date ? |
|
this.toRelativeTime(dueTime - this.now()) : |
|
this.toRelativeTime(dueTime); |
|
|
|
return this.scheduleRelative(state, dt, action); |
|
}; |
|
|
|
/** |
|
* Adds a relative time value to an absolute time value. |
|
* @param {Number} absolute Absolute virtual time value. |
|
* @param {Number} relative Relative virtual time value to add. |
|
* @return {Number} Resulting absolute virtual time sum value. |
|
*/ |
|
VirtualTimeSchedulerPrototype.add = notImplemented; |
|
|
|
/** |
|
* Converts an absolute time to a number |
|
* @param {Any} The absolute time. |
|
* @returns {Number} The absolute time in ms |
|
*/ |
|
VirtualTimeSchedulerPrototype.toAbsoluteTime = notImplemented; |
|
|
|
/** |
|
* Converts the TimeSpan value to a relative virtual time value. |
|
* @param {Number} timeSpan TimeSpan value to convert. |
|
* @return {Number} Corresponding relative virtual time value. |
|
*/ |
|
VirtualTimeSchedulerPrototype.toRelativeTime = notImplemented; |
|
|
|
/** |
|
* Schedules a periodic piece of work by dynamically discovering the scheduler's capabilities. The periodic task will be emulated using recursive scheduling. |
|
* @param {Mixed} state Initial state passed to the action upon the first iteration. |
|
* @param {Number} period Period for running the work periodically. |
|
* @param {Function} action Action to be executed, potentially updating the state. |
|
* @returns {Disposable} The disposable object used to cancel the scheduled recurring action (best effort). |
|
*/ |
|
VirtualTimeSchedulerPrototype.schedulePeriodic = function (state, period, action) { |
|
var s = new SchedulePeriodicRecursive(this, state, period, action); |
|
return s.start(); |
|
}; |
|
|
|
/** |
|
* Schedules an action to be executed after dueTime. |
|
* @param {Mixed} state State passed to the action to be executed. |
|
* @param {Number} dueTime Relative time after which to execute the action. |
|
* @param {Function} action Action to be executed. |
|
* @returns {Disposable} The disposable object used to cancel the scheduled action (best effort). |
|
*/ |
|
VirtualTimeSchedulerPrototype.scheduleRelative = function (state, dueTime, action) { |
|
var runAt = this.add(this.clock, dueTime); |
|
return this.scheduleAbsolute(state, runAt, action); |
|
}; |
|
|
|
/** |
|
* Starts the virtual time scheduler. |
|
*/ |
|
VirtualTimeSchedulerPrototype.start = function () { |
|
if (!this.isEnabled) { |
|
this.isEnabled = true; |
|
do { |
|
var next = this.getNext(); |
|
if (next !== null) { |
|
this.comparer(next.dueTime, this.clock) > 0 && (this.clock = next.dueTime); |
|
next.invoke(); |
|
} else { |
|
this.isEnabled = false; |
|
} |
|
} while (this.isEnabled); |
|
} |
|
}; |
|
|
|
/** |
|
* Stops the virtual time scheduler. |
|
*/ |
|
VirtualTimeSchedulerPrototype.stop = function () { |
|
this.isEnabled = false; |
|
}; |
|
|
|
/** |
|
* Advances the scheduler's clock to the specified time, running all work till that point. |
|
* @param {Number} time Absolute time to advance the scheduler's clock to. |
|
*/ |
|
VirtualTimeSchedulerPrototype.advanceTo = function (time) { |
|
var dueToClock = this.comparer(this.clock, time); |
|
if (this.comparer(this.clock, time) > 0) { throw new ArgumentOutOfRangeError(); } |
|
if (dueToClock === 0) { return; } |
|
if (!this.isEnabled) { |
|
this.isEnabled = true; |
|
do { |
|
var next = this.getNext(); |
|
if (next !== null && this.comparer(next.dueTime, time) <= 0) { |
|
this.comparer(next.dueTime, this.clock) > 0 && (this.clock = next.dueTime); |
|
next.invoke(); |
|
} else { |
|
this.isEnabled = false; |
|
} |
|
} while (this.isEnabled); |
|
this.clock = time; |
|
} |
|
}; |
|
|
|
/** |
|
* Advances the scheduler's clock by the specified relative time, running all work scheduled for that timespan. |
|
* @param {Number} time Relative time to advance the scheduler's clock by. |
|
*/ |
|
VirtualTimeSchedulerPrototype.advanceBy = function (time) { |
|
var dt = this.add(this.clock, time), |
|
dueToClock = this.comparer(this.clock, dt); |
|
if (dueToClock > 0) { throw new ArgumentOutOfRangeError(); } |
|
if (dueToClock === 0) { return; } |
|
|
|
this.advanceTo(dt); |
|
}; |
|
|
|
/** |
|
* Advances the scheduler's clock by the specified relative time. |
|
* @param {Number} time Relative time to advance the scheduler's clock by. |
|
*/ |
|
VirtualTimeSchedulerPrototype.sleep = function (time) { |
|
var dt = this.add(this.clock, time); |
|
if (this.comparer(this.clock, dt) >= 0) { throw new ArgumentOutOfRangeError(); } |
|
|
|
this.clock = dt; |
|
}; |
|
|
|
/** |
|
* Gets the next scheduled item to be executed. |
|
* @returns {ScheduledItem} The next scheduled item. |
|
*/ |
|
VirtualTimeSchedulerPrototype.getNext = function () { |
|
while (this.queue.length > 0) { |
|
var next = this.queue.peek(); |
|
if (next.isCancelled()) { |
|
this.queue.dequeue(); |
|
} else { |
|
return next; |
|
} |
|
} |
|
return null; |
|
}; |
|
|
|
/** |
|
* Schedules an action to be executed at dueTime. |
|
* @param {Mixed} state State passed to the action to be executed. |
|
* @param {Number} dueTime Absolute time at which to execute the action. |
|
* @param {Function} action Action to be executed. |
|
* @returns {Disposable} The disposable object used to cancel the scheduled action (best effort). |
|
*/ |
|
VirtualTimeSchedulerPrototype.scheduleAbsolute = function (state, dueTime, action) { |
|
var self = this; |
|
|
|
function run(scheduler, state1) { |
|
self.queue.remove(si); |
|
return action(scheduler, state1); |
|
} |
|
|
|
var si = new ScheduledItem(this, state, run, dueTime, this.comparer); |
|
this.queue.enqueue(si); |
|
|
|
return si.disposable; |
|
}; |
|
|
|
return VirtualTimeScheduler; |
|
}(Scheduler)); |
|
|
|
/** Provides a virtual time scheduler that uses Date for absolute time and number for relative time. */ |
|
Rx.HistoricalScheduler = (function (__super__) { |
|
inherits(HistoricalScheduler, __super__); |
|
|
|
/** |
|
* Creates a new historical scheduler with the specified initial clock value. |
|
* @constructor |
|
* @param {Number} initialClock Initial value for the clock. |
|
* @param {Function} comparer Comparer to determine causality of events based on absolute time. |
|
*/ |
|
function HistoricalScheduler(initialClock, comparer) { |
|
var clock = initialClock == null ? 0 : initialClock; |
|
var cmp = comparer || defaultSubComparer; |
|
__super__.call(this, clock, cmp); |
|
} |
|
|
|
var HistoricalSchedulerProto = HistoricalScheduler.prototype; |
|
|
|
/** |
|
* Adds a relative time value to an absolute time value. |
|
* @param {Number} absolute Absolute virtual time value. |
|
* @param {Number} relative Relative virtual time value to add. |
|
* @return {Number} Resulting absolute virtual time sum value. |
|
*/ |
|
HistoricalSchedulerProto.add = function (absolute, relative) { |
|
return absolute + relative; |
|
}; |
|
|
|
HistoricalSchedulerProto.toAbsoluteTime = function (absolute) { |
|
return new Date(absolute).getTime(); |
|
}; |
|
|
|
/** |
|
* Converts the TimeSpan value to a relative virtual time value. |
|
* @memberOf HistoricalScheduler |
|
* @param {Number} timeSpan TimeSpan value to convert. |
|
* @return {Number} Corresponding relative virtual time value. |
|
*/ |
|
HistoricalSchedulerProto.toRelativeTime = function (timeSpan) { |
|
return timeSpan; |
|
}; |
|
|
|
return HistoricalScheduler; |
|
}(Rx.VirtualTimeScheduler)); |
|
|
|
return Rx; |
|
}));
|
|
|