I implemented a simple queuing system for my Node.JS app and wanted a critique on it's structure.
const TPS = 20;
const Queue = {
counter: 1,
items: {},
/**
* Add an item to the queue, with the given func to call
* @param {Function} func
* @param {Boolean} repeating
* @return {Number}
*/
add(func, repeating = false) {
const id = this.counter++;
this.items[id] = {func, repeating, id};
return id;
},
/**
* Remove an item from the queue with the given id
* @param {Number} id
*/
remove(id) {
if (this.items.hasOwnProperty(id)) {
delete this.items[id];
}
},
/**
* Process items in the queue
*/
process() {
for (let id in this.items) {
// Prevent this item from being processed again
if (!this.items.hasOwnProperty(id) || this.items[id].processing) {
continue;
}
// Delete this item when it's scheduled for deletion
if (this.items[id].scheduledForDeletion) {
delete this.items[id];
continue;
}
// Let the queue know this item is being processed and
// it's scheduled deletion status
this.items[id].processing = true;
this.items[id].scheduledForDeletion = !this.items[id].repeating;
// Don't wait for item's promise to resolve, since this
// will create a backlog on the queue
(async () => {
try {
await this.items[id].func.call(null);
} catch (err) {
// TODO: Handle errors.
console.error(err);
}
this.items[id].processing = false;
})();
}
}
};
(function tick() {
setTimeout(tick, 1000 / TPS);
Queue.process();
})();
This is an example of how it's implemented.
// Add three items to the queue: 1 normal, 1 async and 1 repeating
Queue.add(() => console.info(`[tick] -> ${Date.now()}`));
Queue.add(async () => setTimeout(() => console.info(`[async] -> ${Date.now()}`), 100));
const timeLoop = Queue.add(() => console.info(`[loop] time (loop) -> ${Date.now()}`), true);
// Remove the looping item from the queue
setTimeout(() => Queue.remove(timeLoop), 500);
The idea is to have this run when the server starts and continually process the queue items. Queue is in it's own file and exported. I import this file into my controllers and call (for example) Queue.add('function to add user to DB and send out email').
process; andasyncatQueue.add(async () => setTimeout(() => console.info(`[async] -> ${Date.now()}`), 100))where noPromiseis included within or returned from the function passed toQueue.add()? IsQueue.add()andprocessexpected to handle both asynchronous and synchronous functions as parameters? \$\endgroup\$awaitkeyword needs to be inside anasyncbody, but I think it might be better to move it to the process function definition likeasync process(). TheQueue.addcalls at the end of my code are just examples to show you that you can add async items to the queue. And actuallyasyncreturns a promise by default so technically they are returning promises. Finally, yes, the process method handles both sync and async items. \$\endgroup\$async () => setTimeout(() => console.info(`[async] -> ${Date.now()}`), 100)return any value? See Why is value undefined at .then() chained to Promise? \$\endgroup\$