index.js 1.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. 'use strict';
  2. const pMap = (iterable, mapper, options) => new Promise((resolve, reject) => {
  3. options = Object.assign({
  4. concurrency: Infinity
  5. }, options);
  6. if (typeof mapper !== 'function') {
  7. throw new TypeError('Mapper function is required');
  8. }
  9. const {concurrency} = options;
  10. if (!(typeof concurrency === 'number' && concurrency >= 1)) {
  11. throw new TypeError(`Expected \`concurrency\` to be a number from 1 and up, got \`${concurrency}\` (${typeof concurrency})`);
  12. }
  13. const ret = [];
  14. const iterator = iterable[Symbol.iterator]();
  15. let isRejected = false;
  16. let isIterableDone = false;
  17. let resolvingCount = 0;
  18. let currentIndex = 0;
  19. const next = () => {
  20. if (isRejected) {
  21. return;
  22. }
  23. const nextItem = iterator.next();
  24. const i = currentIndex;
  25. currentIndex++;
  26. if (nextItem.done) {
  27. isIterableDone = true;
  28. if (resolvingCount === 0) {
  29. resolve(ret);
  30. }
  31. return;
  32. }
  33. resolvingCount++;
  34. Promise.resolve(nextItem.value)
  35. .then(element => mapper(element, i))
  36. .then(
  37. value => {
  38. ret[i] = value;
  39. resolvingCount--;
  40. next();
  41. },
  42. error => {
  43. isRejected = true;
  44. reject(error);
  45. }
  46. );
  47. };
  48. for (let i = 0; i < concurrency; i++) {
  49. next();
  50. if (isIterableDone) {
  51. break;
  52. }
  53. }
  54. });
  55. module.exports = pMap;
  56. // TODO: Remove this for the next major release
  57. module.exports.default = pMap;