@webda/core
Version:
Expose API with Lambda
168 lines • 4.22 kB
JavaScript
/**
* Represent an item within the Throttler
*/
class ThrottlerItem {
constructor(method, callbacks, name) {
this.method = method;
this.callbacks = callbacks;
this.name = name;
}
toString() {
return `${this.name}: ${this.promise ? "IN-PROGRESS" : "QUEUED"}`;
}
}
/**
* Promise Throttler
*
* Allow you to queue promise and execute them concurrently
*
* Several libraries does that
*
* The queue method still gives you a simple Promise linked to the resolution
* of your queued item, so you can still wait for the execution of the specific
* item
*/
export class Throttler {
/**
*
* @param concurrency max concurrent promise to execute
*/
constructor(concurrency = 10) {
this.concurrency = concurrency;
/**
* Current queue
*/
this._queue = [];
/**
* Number of promises in-progress
*/
this.current = 0;
/**
* Resolver for each call to waitForCompletion
*/
this._waiters = [];
}
/**
* Run a Throttler without having to instanciate it
* @param method
* @param concurrency
* @returns
*/
static run(method, concurrency = 10) {
let t = new Throttler(concurrency);
t.queue(method);
return t.wait();
}
/**
* Execute a new promise
*
* Alias for queue
* @param method
* @param name
* @returns
*/
execute(method, name = `Promise_${this.getSize()}`) {
return this.queue(method, name);
}
/**
* Queue a new promise
*
* @param method executor that return the promise to queue
* @param name of the task, usefull when calling getInProgress
* @returns
*/
queue(method, name = `Promise_${this.getSize()}`) {
return new Promise((...callbacks) => {
(Array.isArray(method) ? method : [method]).forEach(m => {
this._queue.push(new ThrottlerItem(m, callbacks, name));
this.add();
});
});
}
/**
* Set the concurrency
* @param concurrency newValue
*
* If decreased, it will be in effect only when current promises resolve
* If increased, it will have immediate effect
*/
setConcurrency(concurrency) {
let oldValue = this.concurrency;
this.concurrency = concurrency;
// Ensure we launch new promise if concurrency has increased
while (oldValue < this.concurrency) {
this.add();
oldValue++;
}
}
/**
* Get inprogress items
* @returns
*/
getInProgress() {
return this._queue.filter(p => p.promise);
}
/**
* Get global queue size
* @returns
*/
getSize() {
return this._queue.length;
}
// REFACTOR . >= 4.0.0
/**
* @deprecated
*/
async waitForCompletion() {
return this.wait();
}
// END_REFACTOR
/**
* Wait until every promise resolve
* @returns
*/
async wait() {
if (this.current === 0) {
return;
}
return new Promise(resolve => {
this._waiters.push(resolve);
});
}
/**
* Internal manage the promise concurrency
* @returns
*/
add() {
if (this.current >= this.concurrency) {
return;
}
const next = this._queue.find(p => !p.promise);
if (!next) {
if (this.current === 0) {
// Call all waiters
this._waiters.forEach(p => p());
this._waiters = [];
}
return;
}
this.current++;
next.promise = next
.method()
.then(res => {
// Call the resolve
next.callbacks[0](res);
})
.catch(err => {
// Call the reject
next.callbacks[1](err);
})
.finally(() => {
this.current--;
// Remove from queue
this._queue.splice(this._queue.indexOf(next), 1);
this.add();
});
}
}
//# sourceMappingURL=throttler.js.map