/** * OOP paradigm */ class Semaphore { constructor(max) { this.tasks = []; this.counter = max; this.dispatch = this.dispatch.bind(this); } dispatch() { if (this.counter > 0 && this.tasks.length > 0) { this.counter--; this.tasks.shift()(); } } release() { this.counter++; this.dispatch(); } acquire() { return new Promise(res => { this.tasks.push(res); setTimeout(this.dispatch, 100); }); } } var semaphore = new Semaphore(2); var run = (async() => { await semaphore.acquire(); console.log('first runner'); await semaphore.acquire(); console.log('second runner'); await semaphore.acquire(); console.log('third runner'); })(); /** * FP paradigm */ let Semaphore = max => { let tasks = []; let counter = max; let dispatch = () => { if (counter > 0 && tasks.length > 0) { counter--; tasks.shift()(); } }; let release = () => { counter++; dispatch(); }; let acquire = () => new Promise(res => { tasks.push(res); /** * Adjust for desired platform */ setTimeout(dispatch); }); return async fn => { await acquire(); let result; try { result = await fn(); } catch (e) { throw e; } finally { release(); } return result; }; }; let semaphore = Semaphore(2); let run = (async () => { let result = await semaphore(async () => { return await Promise.resolve(1); }); return result; })(); /** * Limit */ var limit = (max, fn) => { var semaphore = Semaphore(2); return (...args) => semaphore(() => fn(...args)); }; var doStuff = data => new Promise(res => setTimeout( () => { console.log(data); res(); }, 1000, data ) ); var limitStuffToDo = limit(2, doStuff); limitStuffToDo("one"); limitStuffToDo("two"); limitStuffToDo("3"); limitStuffToDo("four");