index.js 1.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. 'use strict';
  2. module.exports = (iterable, mapper, opts) => new Promise((resolve, reject) => {
  3. opts = Object.assign({
  4. concurrency: Infinity
  5. }, opts);
  6. if (typeof mapper !== 'function') {
  7. throw new TypeError('Mapper function is required');
  8. }
  9. const concurrency = opts.concurrency;
  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 iterableDone = false;
  17. let resolvingCount = 0;
  18. let currentIdx = 0;
  19. const next = () => {
  20. if (isRejected) {
  21. return;
  22. }
  23. const nextItem = iterator.next();
  24. const i = currentIdx;
  25. currentIdx++;
  26. if (nextItem.done) {
  27. iterableDone = true;
  28. if (resolvingCount === 0) {
  29. resolve(ret);
  30. }
  31. return;
  32. }
  33. resolvingCount++;
  34. Promise.resolve(nextItem.value)
  35. .then(el => mapper(el, i))
  36. .then(
  37. val => {
  38. ret[i] = val;
  39. resolvingCount--;
  40. next();
  41. },
  42. err => {
  43. isRejected = true;
  44. reject(err);
  45. }
  46. );
  47. };
  48. for (let i = 0; i < concurrency; i++) {
  49. next();
  50. if (iterableDone) {
  51. break;
  52. }
  53. }
  54. });