forked from lucaspatenaude/ScoreSpot
Update to NPM version
This commit is contained in:
151
ProjectSourceCode/node_modules/spex/lib/ext/batch.js
generated
vendored
Normal file
151
ProjectSourceCode/node_modules/spex/lib/ext/batch.js
generated
vendored
Normal file
@@ -0,0 +1,151 @@
|
||||
const {BatchError} = require('../errors/batch');
|
||||
|
||||
/**
|
||||
* @method batch
|
||||
* @description
|
||||
* Settles (resolves or rejects) every [mixed value]{@tutorial mixed} in the input array.
|
||||
*
|
||||
* The method resolves with an array of results, the same as the standard $[promise.all],
|
||||
* while providing comprehensive error details in case of a reject, in the form of
|
||||
* type {@link errors.BatchError BatchError}.
|
||||
*
|
||||
* @param {Array} values
|
||||
* Array of [mixed values]{@tutorial mixed} (it can be empty), to be resolved asynchronously, in no particular order.
|
||||
*
|
||||
* Passing in anything other than an array will reject with {@link external:TypeError TypeError} =
|
||||
* `Method 'batch' requires an array of values.`
|
||||
*
|
||||
* @param {Object} [options]
|
||||
* Optional Parameters.
|
||||
*
|
||||
* @param {Function|generator} [options.cb]
|
||||
* Optional callback (or generator) to receive the result for each settled value.
|
||||
*
|
||||
* Callback Parameters:
|
||||
* - `index` = index of the value in the source array
|
||||
* - `success` - indicates whether the value was resolved (`true`), or rejected (`false`)
|
||||
* - `result` = resolved data, if `success`=`true`, or else the rejection reason
|
||||
* - `delay` = number of milliseconds since the last call (`undefined` when `index=0`)
|
||||
*
|
||||
* The function inherits `this` context from the calling method.
|
||||
*
|
||||
* It can optionally return a promise to indicate that notifications are handled asynchronously.
|
||||
* And if the returned promise resolves, it signals a successful handling, while any resolved
|
||||
* data is ignored.
|
||||
*
|
||||
* If the function returns a rejected promise or throws an error, the entire method rejects
|
||||
* with {@link errors.BatchError BatchError} where the corresponding value in property `data`
|
||||
* is set to `{success, result, origin}`:
|
||||
* - `success` = `false`
|
||||
* - `result` = the rejection reason or the error thrown by the notification callback
|
||||
* - `origin` = the original data passed into the callback as object `{success, result}`
|
||||
*
|
||||
* @returns {external:Promise}
|
||||
*
|
||||
* The method resolves with an array of individual resolved results, the same as the standard $[promise.all].
|
||||
* In addition, the array is extended with a hidden read-only property `duration` - number of milliseconds
|
||||
* spent resolving all the data.
|
||||
*
|
||||
* The method rejects with {@link errors.BatchError BatchError} when any of the following occurs:
|
||||
* - one or more values rejected or threw an error while being resolved as a [mixed value]{@tutorial mixed}
|
||||
* - notification callback `cb` returned a rejected promise or threw an error
|
||||
*
|
||||
*/
|
||||
function batch(values, options, config) {
|
||||
|
||||
const $p = config.promise, utils = config.utils;
|
||||
|
||||
if (!Array.isArray(values)) {
|
||||
return $p.reject(new TypeError('Method \'batch\' requires an array of values.'));
|
||||
}
|
||||
|
||||
if (!values.length) {
|
||||
const empty = [];
|
||||
utils.extend(empty, 'duration', 0);
|
||||
return $p.resolve(empty);
|
||||
}
|
||||
|
||||
options = options || {};
|
||||
|
||||
const cb = utils.wrap(options.cb),
|
||||
self = this, start = Date.now();
|
||||
|
||||
return $p((resolve, reject) => {
|
||||
let cbTime, remaining = values.length;
|
||||
const errors = [], result = new Array(remaining);
|
||||
values.forEach((item, i) => {
|
||||
utils.resolve.call(self, item, null, data => {
|
||||
result[i] = data;
|
||||
step(i, true, data);
|
||||
}, reason => {
|
||||
result[i] = {success: false, result: reason};
|
||||
errors.push(i);
|
||||
step(i, false, reason);
|
||||
});
|
||||
});
|
||||
|
||||
function step(idx, pass, data) {
|
||||
if (cb) {
|
||||
const cbNow = Date.now(),
|
||||
cbDelay = idx ? (cbNow - cbTime) : undefined;
|
||||
let cbResult;
|
||||
cbTime = cbNow;
|
||||
try {
|
||||
cbResult = cb.call(self, idx, pass, data, cbDelay);
|
||||
} catch (e) {
|
||||
setError(e);
|
||||
}
|
||||
if (utils.isPromise(cbResult)) {
|
||||
cbResult
|
||||
.then(check)
|
||||
.catch(error => {
|
||||
setError(error);
|
||||
check();
|
||||
});
|
||||
} else {
|
||||
check();
|
||||
}
|
||||
} else {
|
||||
check();
|
||||
}
|
||||
|
||||
function setError(e) {
|
||||
const r = pass ? {success: false} : result[idx];
|
||||
if (pass) {
|
||||
result[idx] = r;
|
||||
errors.push(idx);
|
||||
}
|
||||
r.result = e;
|
||||
r.origin = {success: pass, result: data};
|
||||
}
|
||||
|
||||
function check() {
|
||||
if (!--remaining) {
|
||||
if (errors.length) {
|
||||
errors.sort();
|
||||
if (errors.length < result.length) {
|
||||
for (let i = 0, k = 0; i < result.length; i++) {
|
||||
if (i === errors[k]) {
|
||||
k++;
|
||||
} else {
|
||||
result[i] = {success: true, result: result[i]};
|
||||
}
|
||||
}
|
||||
}
|
||||
reject(new BatchError(result, errors, Date.now() - start));
|
||||
} else {
|
||||
utils.extend(result, 'duration', Date.now() - start);
|
||||
resolve(result);
|
||||
}
|
||||
}
|
||||
return null; // this dummy return is just to prevent Bluebird warnings;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = function (config) {
|
||||
return function (values, options) {
|
||||
return batch.call(this, values, options, config);
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user