A semaphore is concurrency construct that is used to limit or throttle access to a resource. This article shows a simple semaphore class in Node.js that can be used to limit execution of functions.
Usage of the class looks like:
// create a semaphore
const sem = new Semaphore(3);
// create a function that is done after 5s
const run = done => {
console.log('starting job');
// call done to release the semaphore
setTimeout(done, 5000);
};
// run this 5 times
sem.take(run);
sem.take(run);
sem.take(run);
sem.take(run);
sem.take(run);
The outpout will immediately start the first three calls to take
. After the first job has finished, the 4th will start. After the second job has finished, the 5ht will start.
Under the covers, our semaphore simply uses a counter to track the number of concurrently executing operations.
class Semaphore {
constructor(max = 1) {
this.max = max;
this._fns = [];
this._active = 0;
}
get remaining() {
return this._fns.length;
}
get active() {
return this._active;
}
take(fn) {
this._fns.push(fn);
this._try();
}
_done() {
this._active -= 1;
this._try();
}
_try() {
if (this._active === this.max || this._fns.length === 0) return;
let fn = this._fns.shift();
this._active += 1;
if (fn) fn(this._done.bind(this));
}
}
This syntax has similarity to the semaphore package on npm. It's so simply, why bother installing another external dependency!