UNPKG

wed

Version:

Wed is a schema-aware editor for XML documents.

157 lines 5.7 kB
/** * Task abstraction for wed. * @author Louis-Dominique Dubeau * @license MPL 2.0 * @copyright Mangalam Research Center for Buddhist Languages */ define(["require", "exports", "rxjs", "rxjs/operators"], function (require, exports, rxjs_1, operators_1) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); /** * A task is a computation that should produce a definite goal after a finite * time. This class is used to allow the task to happen in a way that does not * completely block the JavaScript virtual machine. The task will happen in * cycles that run for a maximum amount of time before relinquishing control. */ class TaskRunner { /** * @param task The computation controlled by this runner. * * @param options The options governing this runner. */ constructor(task, options = {}) { this.task = task; this._timeout = 0; this._maxTimespan = 100; this._boundWrapper = this._workWrapper.bind(this); const keys = ["timeout", "maxTimespan"]; for (const key of keys) { const value = options[key]; if (value === undefined) { continue; } if (value < 0) { throw new Error(`the value for ${key} cannot be negative`); } // tslint:disable-next-line:no-any this[`_${key}`] = options[key]; } this._state = new rxjs_1.BehaviorSubject({ running: false, completed: false, terminated: false, }); this.state = this._state.asObservable(); } get running() { return this._state.value.running; } get completed() { return this._state.value.completed; } get terminated() { return this._state.value.terminated; } onCompleted() { return this.state.pipe(operators_1.first((state) => state.completed)).toPromise(); } _stateFieldChange(field, value) { const latest = this._state.value; const newState = Object.assign({}, this._state.value); newState[field] = value; if (newState[field] !== latest[field]) { this._state.next(newState); } } _setTimeoutId(value) { this._timeoutId = value; this._stateFieldChange("running", this._timeoutId !== undefined); } /** * Marks the task as incomplete and starts processing. */ start() { this.reset(); this.resume(); } /** * Resets the task to its initial state. The task will be deemed incomplete. */ reset() { this._stateFieldChange("completed", false); this.task.reset(this); } /** * Resumes the task. This method does not change the completion status of the * task. So it is possible to stop a task temporarily and resume it later from * where it stopped. */ resume() { if (this.completed) { return; } if (this._timeoutId !== undefined) { this.stop(); } // When we call ``this.resume``, we want the task to resume ASAP. So we do // not use ``this._timeout`` here. However, we do not call // ``this._workWrapper`` directly because we want to be able to call // ``this.resume`` from event handlers. If we did call ``this._workWrapper`` // directly, we'd be calling this._cycle from inside this._cycle this._setTimeoutId(setTimeout(this._boundWrapper, 0)); } /** * Convenience method. The bound version of this method * (``this._boundWrapper``) is what is called by the timeouts. */ _workWrapper() { if (this._work()) { this._setTimeoutId(setTimeout(this._boundWrapper, this._timeout)); } else { this._stateFieldChange("completed", true); } } /** * Keeps the task running by launching cycles only until done or until the * maximum time span for one run is reached. * * @returns False if there is no more work to do. True otherwise. */ _work() { const startDate = Date.now(); // tslint:disable-next-line:strict-boolean-expressions no-constant-condition while (true) { // Give a chance to other operations to work. if ((this._maxTimespan > 0) && (Date.now() - startDate) >= this._maxTimespan) { return true; } const ret = this.task.cycle(this); if (!ret) { return false; } } } /** * Stops the task. */ stop() { if (this._timeoutId !== undefined) { clearTimeout(this._timeoutId); } this._setTimeoutId(undefined); } /** * Terminate the task. */ terminate() { this.stop(); this._stateFieldChange("terminated", true); this._state.complete(); } } exports.TaskRunner = TaskRunner; }); // LocalWords: MPL maxTimespan workWrapper //# sourceMappingURL=task-runner.js.map