@bitblit/ratchet-common
Version:
Common tools for general use
130 lines • 5.58 kB
JavaScript
import { Logger } from '../logger/logger.js';
import { ArrayRatchet } from './array-ratchet.js';
import { TimeoutToken } from './timeout-token.js';
import { StopWatch } from './stop-watch.js';
import { LoggerLevelName } from '../logger/logger-level-name.js';
export class PromiseRatchet {
static resolveOnEvent(evtSrc, okEvtNames, errEvtNames = [], rval = null) {
if (!evtSrc || !okEvtNames || okEvtNames.length === 0 || !evtSrc['on']) {
return Promise.reject('Cannot continue - missing source object or name, or the object is not an event source');
}
return new Promise((res, rej) => {
okEvtNames.forEach((e) => {
evtSrc.on(e, () => {
res(rval);
});
});
if (errEvtNames) {
errEvtNames.forEach((e) => {
evtSrc.on(e, (err) => {
rej(err);
});
});
}
});
}
static timeout(srcPromise, title, timeoutMS) {
return Promise.race([srcPromise, PromiseRatchet.createTimeoutPromise(title, timeoutMS)]);
}
static createTimeoutPromise(title, timeoutMS) {
return new Promise((resolve, reject) => {
const id = setTimeout(() => {
clearTimeout(id);
const rval = new TimeoutToken(title, timeoutMS);
resolve(rval);
}, timeoutMS);
});
}
static async wait(time) {
await PromiseRatchet.createTimeoutPromise('Wait ' + time, time);
Logger.silly('Finished wait of %d ms', time);
}
static dumpResult(result) {
Logger.info('Success, result was : \n\n%s\n\n', JSON.stringify(result));
process.exit(0);
}
static dumpError(err) {
Logger.warn('Failure, err was : \n\n%s\n\n -- \n\n%s\n\n', JSON.stringify(err), String(err));
console.trace();
process.exit(1);
}
static logErrorAndReturnNull(err) {
Logger.warn('Failure, err was : \n\n%s\n\n -- \n\n%s\n\n', JSON.stringify(err), String(err));
return null;
}
static runPromiseAndDump(promise) {
promise.then(PromiseRatchet.dumpResult).catch(PromiseRatchet.dumpError);
}
static async waitFor(testFunction, expectedValue, intervalMS, maxCycles, label = 'waitFor', count = 0) {
if (expectedValue == null || intervalMS < 50 || maxCycles < 1 || count < 0 || typeof testFunction != 'function') {
Logger.warn('%s: Invalid configuration for waitFor - exiting immediately', label);
Logger.warn('ExpectedValue : %s ; interval: %d ; maxCycles: %d ; test : %s', expectedValue, intervalMS, maxCycles, typeof testFunction);
return false;
}
let curVal = null;
try {
curVal = testFunction(count);
}
catch (err) {
Logger.warn('%s: Caught error while waiting, giving up : %s', label, err);
return false;
}
if (curVal === null) {
Logger.debug('%s:CurVal was null - aborting', label);
return false;
}
else if (curVal == expectedValue) {
Logger.debug('%s:Found expected value', label);
return true;
}
else if (count > maxCycles) {
Logger.debug('%s:Exceeded max cycles, giving up', label);
return false;
}
else {
Logger.debug('%s : value not reached yet, waiting (count = %d of %d)', label, count, maxCycles);
await PromiseRatchet.wait(intervalMS);
return PromiseRatchet.waitFor(testFunction, expectedValue, intervalMS, maxCycles, label, count + 1);
}
}
static async runBoundedParallel(promiseFn, params, context, maxConcurrent = 1, logLevel = LoggerLevelName.debug) {
const sw = new StopWatch();
let rval = [];
let remain = params;
Logger.logByLevel(logLevel, 'Processing %d total elements %d at a time', params.length, maxConcurrent);
const ctx = context || this;
let processed = 0;
const totalCount = remain.length;
while (remain.length > 0) {
const curBatch = remain.slice(0, Math.min(remain.length, maxConcurrent));
remain = remain.slice(curBatch.length);
const proms = curBatch.map((c) => promiseFn.apply(ctx, c));
const output = await Promise.all(proms);
processed += proms.length;
rval = rval.concat(output);
const pct = processed / totalCount;
Logger.logByLevel(logLevel, '%d elements remain : %s', remain.length, sw.dumpExpected(pct));
}
sw.log();
return rval;
}
static async runBoundedParallelSingleParam(promiseFn, params, context, maxConcurrent = 1, logLevel = LoggerLevelName.debug) {
const wrappedParams = ArrayRatchet.wrapElementsInArray(params);
return PromiseRatchet.runBoundedParallel(promiseFn, wrappedParams, context, maxConcurrent, logLevel);
}
static async asyncForEachSerial(array, callback) {
for (let index = 0; index < array.length; index++) {
await callback(array[index], index, array);
}
}
static async asyncForEachParallel(array, callback) {
const proms = [];
for (let index = 0; index < array.length; index++) {
proms.push(callback(array[index], index, array));
}
await Promise.all(proms);
}
constructor() {
}
}
//# sourceMappingURL=promise-ratchet.js.map