parallel.js

'use strict';

const { AigleProxy } = require('aigle-core');

const Aigle = require('./aigle');
const {
  INTERNAL,
  PENDING,
  promiseArrayEachWithFunc,
  promiseObjectEachWithFunc,
  promiseMapEachWithFunc,
  promiseSetEachWithFunc,
  iteratorSymbol,
} = require('./internal/util');
const { callResolve, callResolveMap } = require('./props');

class Parallel extends AigleProxy {
  constructor(coll) {
    super();
    this._promise = new Aigle(INTERNAL);
    this._rest = undefined;
    this._result = undefined;
    if (coll === PENDING) {
      this._callResolve = this._set;
    } else {
      this._callResolve = undefined;
      this._set(coll);
    }
  }

  _set(coll) {
    if (Array.isArray(coll)) {
      const size = coll.length;
      this._rest = size;
      this._result = Array(size);
      this._callResolve = callResolve;
      promiseArrayEachWithFunc(this, size, coll);
    } else if (!coll || typeof coll !== 'object') {
      this._rest = 0;
      this._result = {};
    } else if (coll[iteratorSymbol]) {
      const size = coll.size;
      this._rest = size;
      if (coll instanceof Map) {
        const result = new Map();
        this._result = result;
        this._callResolve = callResolveMap;
        promiseMapEachWithFunc(this, Infinity, coll, result);
      } else {
        this._result = Array(this._rest);
        this._callResolve = callResolve;
        promiseSetEachWithFunc(this, Infinity, coll);
      }
    } else {
      const result = {};
      const keys = Object.keys(coll);
      const size = keys.length;
      this._rest = size;
      this._result = result;
      this._callResolve = callResolve;
      promiseObjectEachWithFunc(this, size, coll, result, keys);
    }
    if (this._rest === 0) {
      this._promise._resolve(this._result);
    }
    return this;
  }

  _execute() {
    return this._promise;
  }

  _callReject(reason) {
    this._promise._reject(reason);
  }
}

module.exports = { parallel, Parallel };

/**
 * `Aigle.parallel` functionality is similar to [`Aigle.all`](https://suguru03.github.io/aigle/docs/global.html#all)
 * and [`Aigle.props`](https://suguru03.github.io/aigle/docs/global.html#props), and the function allows function collection.
 * @param {Array|Object} collection - it should be an array/object of functions or Promise instances
 * @example
 *   Aigle.parallel([
 *     () => Aigle.delay(30, 1),
 *     Aigle.delay(20, 2),
 *     3
 *   ]).then(array => {
 *     console.log(array); // [1, 2, 3]
 *   });
 *
 * @example
 *   Aigle.parallel({
 *     a: () => Aigle.delay(30, 1),
 *     b: Aigle.delay(20, 2),
 *     c: 3
 *   }).then(obj => {
 *     console.log(obj); // { a: 1, b: 2, c: 3 }
 *   });
 */
function parallel(collection) {
  return new Parallel(collection)._promise;
}