UNPKG

@most/scheduler

Version:

Reactive programming with lean, functions-only, curried, tree-shakeable API

441 lines (427 loc) 15.2 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@most/prelude')) : typeof define === 'function' && define.amd ? define(['exports', '@most/prelude'], factory) : (global = global || self, factory(global.mostScheduler = {}, global.mostPrelude)); }(this, (function (exports, prelude) { 'use strict'; var ScheduledTaskImpl = /** @class */ (function () { function ScheduledTaskImpl(time, localOffset, period, task, scheduler) { this.time = time; this.localOffset = localOffset; this.period = period; this.task = task; this.scheduler = scheduler; this.active = true; } ScheduledTaskImpl.prototype.run = function () { return this.task.run(this.time - this.localOffset); }; ScheduledTaskImpl.prototype.error = function (e) { return this.task.error(this.time - this.localOffset, e); }; ScheduledTaskImpl.prototype.dispose = function () { this.active = false; this.scheduler.cancel(this); return this.task.dispose(); }; return ScheduledTaskImpl; }()); var RelativeScheduler = /** @class */ (function () { function RelativeScheduler(origin, scheduler) { this.origin = origin; this.scheduler = scheduler; } RelativeScheduler.prototype.currentTime = function () { return this.scheduler.currentTime() - this.origin; }; RelativeScheduler.prototype.scheduleTask = function (localOffset, delay, period, task) { return this.scheduler.scheduleTask(localOffset + this.origin, delay, period, task); }; RelativeScheduler.prototype.relative = function (origin) { return new RelativeScheduler(origin + this.origin, this.scheduler); }; RelativeScheduler.prototype.cancel = function (task) { return this.scheduler.cancel(task); }; RelativeScheduler.prototype.cancelAll = function (f) { return this.scheduler.cancelAll(f); }; return RelativeScheduler; }()); /** @license MIT License (c) copyright 2010-2017 original author or authors */ var defer = function (task) { return Promise.resolve(task).then(runTask); }; function runTask(task) { try { return task.run(); } catch (e) { return task.error(e); } } /** @license MIT License (c) copyright 2010-2017 original author or authors */ var SchedulerImpl = /** @class */ (function () { function SchedulerImpl(timer, timeline) { var _this = this; this._runReadyTasksBound = function () { return _this._runReadyTasks(); }; this.timer = timer; this.timeline = timeline; this._timer = null; this._nextArrival = Infinity; } SchedulerImpl.prototype.currentTime = function () { return this.timer.now(); }; SchedulerImpl.prototype.scheduleTask = function (localOffset, delay, period, task) { var time = this.currentTime() + Math.max(0, delay); var st = new ScheduledTaskImpl(time, localOffset, period, task, this); this.timeline.add(st); this._scheduleNextRun(); return st; }; SchedulerImpl.prototype.relative = function (offset) { return new RelativeScheduler(offset, this); }; SchedulerImpl.prototype.cancel = function (task) { task.active = false; if (this.timeline.remove(task)) { this._reschedule(); } }; // @deprecated SchedulerImpl.prototype.cancelAll = function (f) { this.timeline.removeAll(f); this._reschedule(); }; SchedulerImpl.prototype._reschedule = function () { if (this.timeline.isEmpty()) { this._unschedule(); } else { this._scheduleNextRun(); } }; SchedulerImpl.prototype._unschedule = function () { this.timer.clearTimer(this._timer); this._timer = null; }; SchedulerImpl.prototype._scheduleNextRun = function () { if (this.timeline.isEmpty()) { return; } var nextArrival = this.timeline.nextArrival(); if (this._timer === null) { this._scheduleNextArrival(nextArrival); } else if (nextArrival < this._nextArrival) { this._unschedule(); this._scheduleNextArrival(nextArrival); } }; SchedulerImpl.prototype._scheduleNextArrival = function (nextArrival) { this._nextArrival = nextArrival; var delay = Math.max(0, nextArrival - this.currentTime()); this._timer = this.timer.setTimer(this._runReadyTasksBound, delay); }; SchedulerImpl.prototype._runReadyTasks = function () { this._timer = null; this.timeline.runTasks(this.currentTime(), runTask); this._scheduleNextRun(); }; return SchedulerImpl; }()); /** @license MIT License (c) copyright 2010-2017 original author or authors */ var TimelineImpl = /** @class */ (function () { function TimelineImpl() { this.tasks = []; } TimelineImpl.prototype.nextArrival = function () { return this.isEmpty() ? Infinity : this.tasks[0].time; }; TimelineImpl.prototype.isEmpty = function () { return this.tasks.length === 0; }; TimelineImpl.prototype.add = function (st) { insertByTime(st, this.tasks); }; TimelineImpl.prototype.remove = function (st) { var i = binarySearch(getTime(st), this.tasks); if (i >= 0 && i < this.tasks.length) { var events = this.tasks[i].events; var at = prelude.findIndex(st, events); if (at >= 0) { events.splice(at, 1); if (events.length === 0) { this.tasks.splice(i, 1); } return true; } } return false; }; /** * @deprecated */ TimelineImpl.prototype.removeAll = function (f) { for (var i = 0; i < this.tasks.length; ++i) { removeAllFrom(f, this.tasks[i]); } }; TimelineImpl.prototype.runTasks = function (t, runTask) { var tasks = this.tasks; var l = tasks.length; var i = 0; while (i < l && tasks[i].time <= t) { ++i; } this.tasks = tasks.slice(i); // Run all ready tasks for (var j = 0; j < i; ++j) { this.tasks = runReadyTasks(runTask, tasks[j].events, this.tasks); } }; return TimelineImpl; }()); function runReadyTasks(runTask, events, tasks) { for (var i = 0; i < events.length; ++i) { var task = events[i]; if (task.active) { runTask(task); // Reschedule periodic repeating tasks // Check active again, since a task may have canceled itself if (task.period >= 0 && task.active) { task.time = task.time + task.period; insertByTime(task, tasks); } } } return tasks; } function insertByTime(task, timeslots) { var l = timeslots.length; var time = getTime(task); if (l === 0) { timeslots.push(newTimeslot(time, [task])); return; } var i = binarySearch(time, timeslots); if (i >= l) { timeslots.push(newTimeslot(time, [task])); } else { insertAtTimeslot(task, timeslots, time, i); } } function insertAtTimeslot(task, timeslots, time, i) { var timeslot = timeslots[i]; if (time === timeslot.time) { addEvent(task, timeslot.events); } else { timeslots.splice(i, 0, newTimeslot(time, [task])); } } function addEvent(task, events) { if (events.length === 0 || task.time >= events[events.length - 1].time) { events.push(task); } else { spliceEvent(task, events); } } function spliceEvent(task, events) { for (var j = 0; j < events.length; j++) { if (task.time < events[j].time) { events.splice(j, 0, task); break; } } } function getTime(scheduledTask) { return Math.floor(scheduledTask.time); } /** * @deprecated */ function removeAllFrom(f, timeslot) { timeslot.events = prelude.removeAll(f, timeslot.events); } function binarySearch(t, sortedArray) { var lo = 0; var hi = sortedArray.length; var mid, y; while (lo < hi) { mid = Math.floor((lo + hi) / 2); y = sortedArray[mid]; if (t === y.time) { return mid; } else if (t < y.time) { hi = mid; } else { lo = mid + 1; } } return hi; } var newTimeslot = function (t, events) { return ({ time: t, events: events }); }; /** @license MIT License (c) copyright 2010-2017 original author or authors */ /* global setTimeout, clearTimeout */ var ClockTimer = /** @class */ (function () { function ClockTimer(clock) { this._clock = clock; } ClockTimer.prototype.now = function () { return this._clock.now(); }; ClockTimer.prototype.setTimer = function (f, dt) { return dt <= 0 ? runAsap(f) : setTimeout(f, dt); }; ClockTimer.prototype.clearTimer = function (t) { return t instanceof Asap ? t.cancel() : clearTimeout(t); }; return ClockTimer; }()); var Asap = /** @class */ (function () { function Asap(f) { this.f = f; this.active = true; } Asap.prototype.run = function () { if (this.active) { return this.f(); } }; Asap.prototype.error = function (e) { throw e; }; Asap.prototype.cancel = function () { this.active = false; }; return Asap; }()); function runAsap(f) { var task = new Asap(f); defer(task); return task; } /* global performance, process */ var RelativeClock = /** @class */ (function () { function RelativeClock(clock, origin) { this.origin = origin; this.clock = clock; } RelativeClock.prototype.now = function () { return this.clock.now() - this.origin; }; return RelativeClock; }()); var HRTimeClock = /** @class */ (function () { function HRTimeClock(hrtime, origin) { this.origin = origin; this.hrtime = hrtime; } HRTimeClock.prototype.now = function () { var hrt = this.hrtime(this.origin); return (hrt[0] * 1e9 + hrt[1]) / 1e6; }; return HRTimeClock; }()); var clockRelativeTo = function (clock) { return new RelativeClock(clock, clock.now()); }; var newPerformanceClock = function () { return clockRelativeTo(performance); }; /** * @deprecated will be removed in 2.0.0 * Date.now is not monotonic, and performance.now is ubiquitous: * @see https://caniuse.com/#search=performance.now */ var newDateClock = function () { return clockRelativeTo(Date); }; var newHRTimeClock = function () { return new HRTimeClock(process.hrtime, process.hrtime()); }; var newPlatformClock = function () { if (typeof performance !== 'undefined' && typeof performance.now === 'function') { return newPerformanceClock(); } else if (typeof process !== 'undefined' && typeof process.hrtime === 'function') { return newHRTimeClock(); } return newDateClock(); }; /** * Read the current time from the provided Scheduler */ var currentTime = function (scheduler) { return scheduler.currentTime(); }; /** * Schedule a task to run as soon as possible, but * not in the current call stack */ var asap = prelude.curry2(function (task, scheduler) { return scheduler.scheduleTask(0, 0, -1, task); }); /** * Schedule a task to run after a millisecond delay */ var delay = prelude.curry3(function (delay, task, scheduler) { return scheduler.scheduleTask(0, delay, -1, task); }); /** * Schedule a task to run periodically, with the * first run starting asap */ var periodic = prelude.curry3(function (period, task, scheduler) { return scheduler.scheduleTask(0, 0, period, task); }); /** * Cancel a scheduledTask */ var cancelTask = function (scheduledTask) { return scheduledTask.dispose(); }; /** * Cancel all ScheduledTasks for which a predicate is true * @deprecated Will be removed in 2.0.0 */ var cancelAllTasks = prelude.curry2(function (predicate, scheduler) { console.warn("DEPRECATED cancelAllTasks to be removed in 2.0.0"); return scheduler.cancelAll(predicate); }); var schedulerRelativeTo = prelude.curry2(function (offset, scheduler) { return new RelativeScheduler(offset, scheduler); }); /** @license MIT License (c) copyright 2010-2017 original author or authors */ var newScheduler = prelude.curry2(function (timer, timeline) { return new SchedulerImpl(timer, timeline); }); var newDefaultScheduler = function () { return new SchedulerImpl(newDefaultTimer(), new TimelineImpl()); }; var newDefaultTimer = function () { return new ClockTimer(newPlatformClock()); }; var newClockTimer = function (clock) { return new ClockTimer(clock); }; var newTimeline = function () { return new TimelineImpl(); }; exports.HRTimeClock = HRTimeClock; exports.RelativeClock = RelativeClock; exports.asap = asap; exports.cancelAllTasks = cancelAllTasks; exports.cancelTask = cancelTask; exports.clockRelativeTo = clockRelativeTo; exports.currentTime = currentTime; exports.delay = delay; exports.newClockTimer = newClockTimer; exports.newDateClock = newDateClock; exports.newDefaultScheduler = newDefaultScheduler; exports.newDefaultTimer = newDefaultTimer; exports.newHRTimeClock = newHRTimeClock; exports.newPerformanceClock = newPerformanceClock; exports.newPlatformClock = newPlatformClock; exports.newScheduler = newScheduler; exports.newTimeline = newTimeline; exports.periodic = periodic; exports.schedulerRelativeTo = schedulerRelativeTo; Object.defineProperty(exports, '__esModule', { value: true }); }))); //# sourceMappingURL=index.js.map