I am following an example of a book (Node.js design patterns) to implement a LIMITED PARALLEL EXECUTION algorithm in Node.js with Javascript.
First, I write a TaskQueue class that handles all the limiting and execution of the tasks.
class TaskQueue {
constructor(concurrency) {
this.concurrency = concurrency;
this.running = 0;
this.queue = [];
}
runTask(task) {
return new Promise((resolve, reject) => {
this.queue.push(() => {
return task().then(resolve, reject);
});
process.nextTick(this.next.bind(this));
});
}
next() {
while (this.running < this.concurrency && this.queue.length) {
const task = this.queue.shift();
task().finally(() => {
this.running--;
this.next();
});
this.running++;
}
}
}
Then I have written a function that returns a promise that resolves after a random number of miliseconds and keeps record of the promise with an assigned number.
This function delegates the task to the queue, wrapping the promise in a function that will be executed on demand by the TaskQueue class.
function promiseResolveRandomValue(promiseNumber, queue) {
return queue.runTask(() => {
return new Promise(resolve => {
const random = Math.round(Math.random()*1000);
setTimeout(() => {
console.log('Resolved promise number: ', promiseNumber, ' with delay of: ', random);
resolve();
}, random);
});
})
}
Finally I have used a map to execute the function over an array of ten numbers that will help us keep track of each promise.
const queue = new TaskQueue(2);
const array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
const promises = array.map((number) => {
return promiseResolveRandomValue(number, queue);
});
Promise.all(promises)
.then(() => console.log('Finished'));
So far so good. The thing is that the author recommends this line of code to be executed with process.nextTick to avoid any Zalgo type of situation, but I don't see why, as this code executes exactly the same just invoking the next method of the class.
runTask(task) {
return new Promise((resolve, reject) => {
this.queue.push(() => {
return task().then(resolve, reject);
});
process.nextTick(this.next.bind(this)); // <-------------------------------- WHY?
});
}
Could someone clarify why is it convenient to use the process.nextTick in some cases such as this one to avoid conflicts with synchronous and asynchronous code?