blaze-2d
Version:
A fast and simple WebGL 2 2D game engine written in TypeScript
151 lines • 4.66 kB
JavaScript
export default class Thread {
/**
* Creates a {@link Thread} instance, sets up it's worker and starts it's cleaning loop.
*
* @param id A string to be used as an identifier for this thread.
*/
constructor(id) {
this.inUse = false;
this.queue = [];
this.maxQueueSize = Infinity; // maximum size a thread's queue can be before main thread must be used
this.cleanRate = 100; // rate at which the queue is checked for hanging tasks that need to be executed in ms
this.id = id;
this.setupWorker();
this.clean();
}
/**
* Sets up the thread's worker and it's associated events.
*/
setupWorker() {
this.worker = new Worker(new URL("worker", import.meta.url), { type: "module" });
this.worker.onmessage = (e) => this.handleMessage(e.data);
this.worker.onerror = (e) => this.log(e);
this.worker.onmessageerror = (e) => this.log(e);
}
/**
* Handles a message from the thread's worker
*
* @param msg The message received from the worker
*/
handleMessage(msg) {
// this.log(msg);
switch (msg.task) {
case "completed":
if (this.currentTask.cb)
this.currentTask.cb(msg.data);
this.nextTask();
break;
default:
break;
}
}
/**
* Attempts to run a task on the thread or add it to the queue.
*
* @param task The task to run or queue.
* @param skipQueue If true then the max queue size is ignored and the task is prepended to the front of the queue
* @returns True when the task is ran or queued, false otherwise
*/
addTask(task, skipQueue = false) {
if (skipQueue) {
if (this.inUse)
this.queue.unshift(task);
else {
this.sendTask(task);
}
return true;
}
if (this.inUse && this.queue.length < this.maxQueueSize) {
this.queue.push(task);
return true;
}
else if (!this.inUse) {
let chosen = task;
if (this.queue.length > 0) {
this.queue.push(task);
chosen = this.queue.shift();
}
this.sendTask(chosen);
return true;
}
return false;
}
/**
* Sends a task to the thread's worker, saves a reference to the sent task and marks the thread as in use.
*
* No checks are made to see if the thread is in use before sending the task.
*
* @param task The task to send to the thread's worker.
*/
sendTask(task) {
this.currentTask = task;
this.inUse = true;
this.worker.postMessage({ task: task.task, data: task.data });
}
/**
* Sends the next task in the thread's queue to it's worker.
*
* If the queue is empty then the thread marks itself as not in use.
*/
nextTask() {
if (this.queue.length === 0) {
this.inUse = false;
return;
}
this.sendTask(this.queue.shift());
}
/**
* Attempts to clean out the thread's queue whenever the thread has hung.
*
* A hung thread is one in which the thread is not in use but it has task(s) in it's queue.
*/
clean() {
if (!this.inUse && this.queue.length > 0) {
this.sendTask(this.queue.shift());
}
setTimeout(() => this.clean(), this.cleanRate);
}
/**
* Returns wether the thread is currently in use.
*
* This is true when the thread's worker is currently processing a task.
*
* @returns If the thread is currently in use.
*/
getInUse() {
return this.inUse;
}
/**
* A thread is free when it is not in use or the queue size is below the thread's maximum queue size
*
* @returns true/false depending on if the thread is free
*/
isFree() {
return !this.inUse || this.queue.length < this.maxQueueSize;
}
/**
* Gets the number of task in the thread's queue.
*
* @returns The length of the thread's queue.
*/
getNumInQueue() {
return this.queue.length;
}
/**
* Gets the thread's id.
*
* @returns The thread's id
*/
getId() {
return this.id;
}
/**
* Prepends a console.log call with the thread's id.
*
* @param params Params for `console.log`
*/
log(...params) {
console.log(`[${this.id}]:`, ...params);
}
}
//# sourceMappingURL=thread.js.map