/**
* This class is used for task management. Tasks are processed in an asynchronous
* way when there is idle time within a single simulation step or after a defined amount
* of time (deadline). The class is a wrapper around {@link https://w3.org/TR/requestidlecallback|requestidlecallback()},
* a JavaScript API for cooperative scheduling of background tasks.
*
* @author {@link https://github.com/robp94|robp94}
*/
class TaskQueue {
/**
* Constructs a new task queue.
*/
constructor() {
/**
* A list of pending tasks.
* @type {Array<Task>}
* @readonly
*/
this.tasks = new Array();
/**
* Used to control the asynchronous processing.
* - timeout: After this amount of time (in ms), a scheduled task is executed even if
* doing so risks causing a negative performance impact (e.g. bad frame time).
* @type {Object}
*/
this.options = {
timeout: 1000 // ms
};
//
this._active = false;
this._handler = runTaskQueue.bind( this );
this._taskHandle = 0;
}
/**
* Adds the given task to the task queue.
*
* @param {Task} task - The task to add.
* @return {TaskQueue} A reference to this task queue.
*/
enqueue( task ) {
this.tasks.push( task );
return this;
}
/**
* Updates the internal state of the task queue. Should be called
* per simulation step.
*
* @return {TaskQueue} A reference to this task queue.
*/
update() {
if ( this.tasks.length > 0 ) {
if ( this._active === false ) {
this._taskHandle = requestIdleCallback( this._handler, this.options );
this._active = true;
}
} else {
this._active = false;
}
return this;
}
}
/**
* This function controls the processing of tasks. It schedules tasks when there
* is idle time at the end of a simulation step.
*
* @param {Object} deadline - This object contains a function which returns
* a number indicating how much time remains for task processing.
*/
function runTaskQueue( deadline ) {
const tasks = this.tasks;
while ( deadline.timeRemaining() > 0 && tasks.length > 0 ) {
const task = tasks[ 0 ];
task.execute();
tasks.shift();
}
if ( tasks.length > 0 ) {
this._taskHandle = requestIdleCallback( this._handler, this.options );
this._active = true;
} else {
this._taskHandle = 0;
this._active = false;
}
}
export { TaskQueue };