promise-useful-utils
Version:
useful functions for working with promises
281 lines (234 loc) • 6.79 kB
JavaScript
;
var _Promise = require('babel-runtime/core-js/promise')['default'];
var _Object$keys = require('babel-runtime/core-js/object/keys')['default'];
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.props = props;
exports.settle = settle;
exports.some = some;
exports.map = map;
exports.reduce = reduce;
exports.filter = filter;
exports.each = each;
var _errors = require('./errors');
/**
* @param {Object}
* @return {Promise.<Object>}
*/
function props(obj) {
return _Promise.resolve().then(function () {
var type = typeof obj;
if (!(!!obj && type === 'object')) {
throw new TypeError('cannot await properties of a non-object');
}
var keys = _Object$keys(obj);
return _Promise.all(keys.map(function (key) {
return obj[key];
})).then(function (values) {
var result = {};
for (var index = 0; index < values.length; ++index) {
result[keys[index]] = values[index];
}
return result;
});
});
}
/**
* @param {Array.<*>} args
* @return {Promise.<Array.<*>>}
*/
function settle(args) {
if (!Array.isArray(args)) {
return _Promise.reject(new TypeError('expecting an array'));
}
if (args.length === 0) {
return _Promise.resolve([]);
}
return new _Promise(function (resolve) {
var ready = 0;
var values = new Array(args.length);
var _loop = function (index) {
_Promise.resolve(args[index]).then(function (value) {
values[index] = { value: value };
}, function (err) {
values[index] = { reason: err };
}).then(function () {
ready += 1;
if (ready === args.length) {
resolve(values);
}
});
};
for (var index = 0; index < args.length; ++index) {
_loop(index);
}
});
}
/**
* @param {Array.<*>} args
* @param {number} [count=1]
* @return {Promise.<Array.<*>>}
*/
function some(args, count) {
if (!Array.isArray(args)) {
return _Promise.reject(new TypeError('expecting an array'));
}
count = parseInt(count, 10);
if (isNaN(count) || count < 0) {
return _Promise.reject(new TypeError('expecting a positive integer'));
}
if (count === 0) {
return _Promise.resolve([]);
}
if (count > args.length) {
return _Promise.reject(new RangeError('Input array must contain at least ' + count + ' items but contains only ' + args.length + ' items'));
}
var values = [];
var reasons = [];
return new _Promise(function (resolve, reject) {
for (var index = 0; index < args.length; ++index) {
args[index].then(function (value) {
values.push(value);
if (values.length === count) {
resolve(values);
}
}, function (err) {
reasons.push(err);
if (reasons.length + count > args.length) {
err = new _errors.AggregateError();
err.reasons = reasons;
reject(err);
}
});
}
});
}
/**
* @param {Array.<*>} args
* @param {function} mapper
* @param {Object} [options]
* @param {number} [options.concurrency = Infinity]
* @return {Promise.<Array.<*>>}
*/
function map(args, mapper) {
var options = arguments.length <= 2 || arguments[2] === undefined ? { concurrency: Infinity } : arguments[2];
if (!Array.isArray(args)) {
return _Promise.reject(new TypeError('expecting an array'));
}
if (args.length === 0) {
return _Promise.resolve([]);
}
if (typeof mapper !== 'function') {
return _Promise.reject(new TypeError('fn must be a function'));
}
var concurrency = Object(options).concurrency;
if (concurrency === Infinity) {
concurrency = args.length;
}
concurrency = parseInt(concurrency, 10);
if (isNaN(concurrency) || concurrency < 0) {
return _Promise.reject(new TypeError('expecting a positive integer'));
}
if (concurrency > args.length) {
return _Promise.reject(new RangeError('Input array must contain at least ' + concurrency + ' items but contains only ' + args.length + ' items'));
}
return new _Promise(function (resolve, reject) {
var ready = 0;
var values = new Array(args.length);
var isRejected = false;
function next(index) {
if (index >= args.length || isRejected) {
if (ready === args.length) {
resolve(values);
}
return;
}
_Promise.resolve(args[index]).then(function (item) {
return mapper(item, index, args);
}).then(function (value) {
ready += 1;
values[index] = value;
next(index + concurrency);
}, function (err) {
isRejected = true;
reject(err);
});
}
for (var index = 0; index < concurrency; ++index) {
next(index);
}
});
}
/**
* @param {Array.<*>} args
* @param {function} reducer
* @param {*} [initialValue]
* @return {Promise.<*>}
*/
function reduce(args, reducer, initialValue) {
if (!Array.isArray(args)) {
return _Promise.reject(new TypeError('expecting an array'));
}
if (typeof reducer !== 'function') {
return _Promise.reject(new TypeError('fn must be a function'));
}
return new _Promise(function (resolve, reject) {
var total = initialValue;
function next(index) {
if (index === args.length) {
return resolve(total);
}
_Promise.resolve(args[index]).then(function (item) {
return reducer(total, item, index, args);
}).then(function (value) {
total = value;
next(index + 1);
}, function (err) {
reject(err);
});
}
next(0);
});
}
/**
* @param {Array.<*>} args
* @param {function} filterer
* @param {Object} [options]
* @param {number} [options.concurrency = Infinity]
* @return {Promise.<Array.<*>>}
*/
function filter(args, filterer) {
var options = arguments.length <= 2 || arguments[2] === undefined ? { concurrency: Infinity } : arguments[2];
if (typeof filterer !== 'function') {
return _Promise.reject(new TypeError('fn must be a function'));
}
return map(args, function (item, index, args) {
return _Promise.resolve(filterer(item, index, args)).then(function (isValid) {
return [isValid, item];
});
}, options).then(function (items) {
return items.filter(function (item) {
return item[0];
}).map(function (item) {
return item[1];
});
});
}
/**
* @param {Array.<*>} args
* @param {function} iterator
* @return {Promise.<Array.<*>>}
*/
function each(args, iterator) {
if (typeof iterator !== 'function') {
return _Promise.reject(new TypeError('fn must be a function'));
}
var values = [];
return reduce(args, function (_, item, index) {
values.push(item);
return iterator(item, index, args);
}).then(function () {
return values;
});
}