diagram-js
Version:
A toolbox for displaying and modifying diagrams on the web
122 lines (94 loc) • 2.27 kB
JavaScript
import IdGenerator from '../../util/IdGenerator';
const Ids = new IdGenerator();
/**
* @typedef { {
* promise: Promise<unknown>,
* executionId: number
* } } ScheduledTask
*/
/**
* A utility that allows you to schedule async tasks.
*
* @class
* @constructor
*
* @param { import('../core/EventBus').default } eventBus
*/
export default function Scheduler(eventBus) {
/**
* @type { Record<string, ScheduledTask> }
*/
this._scheduled = {};
eventBus.on('diagram.destroy', () => {
Object.keys(this._scheduled).forEach(id => {
this.cancel(id);
});
});
}
Scheduler.$inject = [ 'eventBus' ];
/**
* Schedule execution of a task in the next tick.
*
* Call with an id to ensure only the latest call will be executed.
*
* @template T
* @param {(...args: any[]) => T} taskFn function to be executed
* @param {string} [id] identifying the task to ensure uniqueness
*
* @return Promise<T> result of the executed task
*/
Scheduler.prototype.schedule = function(taskFn, id = Ids.next()) {
this.cancel(id);
const newScheduled = this._schedule(taskFn, id);
this._scheduled[id] = newScheduled;
return newScheduled.promise;
};
Scheduler.prototype._schedule = function(taskFn, id) {
const deferred = defer();
const executionId = setTimeout(() => {
try {
this._scheduled[id] = null;
try {
deferred.resolve(taskFn());
} catch (error) {
deferred.reject(error);
}
} catch (error) {
console.error('Scheduler#_schedule execution failed', error);
}
});
return {
executionId,
promise: deferred.promise
};
};
/**
* Cancel a previously scheduled task.
*
* @param {string} id
*/
Scheduler.prototype.cancel = function(id) {
const scheduled = this._scheduled[id];
if (scheduled) {
this._cancel(scheduled);
this._scheduled[id] = null;
}
};
Scheduler.prototype._cancel = function(scheduled) {
clearTimeout(scheduled.executionId);
};
/**
* @return { {
* promise: Promise,
* resolve: Function,
* reject: Function
* } }
*/
function defer() {
const deferred = {};
deferred.promise = new Promise((resolve, reject) => {
deferred.resolve = resolve;
deferred.reject = reject;
});
return deferred;
}