• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"use strict";
2module.exports = function(Promise,
3                          PromiseArray,
4                          apiRejection,
5                          tryConvertToPromise,
6                          INTERNAL,
7                          debug) {
8var getDomain = Promise._getDomain;
9var util = require("./util");
10var tryCatch = util.tryCatch;
11var errorObj = util.errorObj;
12var async = Promise._async;
13
14function MappingPromiseArray(promises, fn, limit, _filter) {
15    this.constructor$(promises);
16    this._promise._captureStackTrace();
17    var domain = getDomain();
18    this._callback = domain === null ? fn : util.domainBind(domain, fn);
19    this._preservedValues = _filter === INTERNAL
20        ? new Array(this.length())
21        : null;
22    this._limit = limit;
23    this._inFlight = 0;
24    this._queue = [];
25    async.invoke(this._asyncInit, this, undefined);
26}
27util.inherits(MappingPromiseArray, PromiseArray);
28
29MappingPromiseArray.prototype._asyncInit = function() {
30    this._init$(undefined, -2);
31};
32
33MappingPromiseArray.prototype._init = function () {};
34
35MappingPromiseArray.prototype._promiseFulfilled = function (value, index) {
36    var values = this._values;
37    var length = this.length();
38    var preservedValues = this._preservedValues;
39    var limit = this._limit;
40
41    if (index < 0) {
42        index = (index * -1) - 1;
43        values[index] = value;
44        if (limit >= 1) {
45            this._inFlight--;
46            this._drainQueue();
47            if (this._isResolved()) return true;
48        }
49    } else {
50        if (limit >= 1 && this._inFlight >= limit) {
51            values[index] = value;
52            this._queue.push(index);
53            return false;
54        }
55        if (preservedValues !== null) preservedValues[index] = value;
56
57        var promise = this._promise;
58        var callback = this._callback;
59        var receiver = promise._boundValue();
60        promise._pushContext();
61        var ret = tryCatch(callback).call(receiver, value, index, length);
62        var promiseCreated = promise._popContext();
63        debug.checkForgottenReturns(
64            ret,
65            promiseCreated,
66            preservedValues !== null ? "Promise.filter" : "Promise.map",
67            promise
68        );
69        if (ret === errorObj) {
70            this._reject(ret.e);
71            return true;
72        }
73
74        var maybePromise = tryConvertToPromise(ret, this._promise);
75        if (maybePromise instanceof Promise) {
76            maybePromise = maybePromise._target();
77            var bitField = maybePromise._bitField;
78            ;
79            if (((bitField & 50397184) === 0)) {
80                if (limit >= 1) this._inFlight++;
81                values[index] = maybePromise;
82                maybePromise._proxy(this, (index + 1) * -1);
83                return false;
84            } else if (((bitField & 33554432) !== 0)) {
85                ret = maybePromise._value();
86            } else if (((bitField & 16777216) !== 0)) {
87                this._reject(maybePromise._reason());
88                return true;
89            } else {
90                this._cancel();
91                return true;
92            }
93        }
94        values[index] = ret;
95    }
96    var totalResolved = ++this._totalResolved;
97    if (totalResolved >= length) {
98        if (preservedValues !== null) {
99            this._filter(values, preservedValues);
100        } else {
101            this._resolve(values);
102        }
103        return true;
104    }
105    return false;
106};
107
108MappingPromiseArray.prototype._drainQueue = function () {
109    var queue = this._queue;
110    var limit = this._limit;
111    var values = this._values;
112    while (queue.length > 0 && this._inFlight < limit) {
113        if (this._isResolved()) return;
114        var index = queue.pop();
115        this._promiseFulfilled(values[index], index);
116    }
117};
118
119MappingPromiseArray.prototype._filter = function (booleans, values) {
120    var len = values.length;
121    var ret = new Array(len);
122    var j = 0;
123    for (var i = 0; i < len; ++i) {
124        if (booleans[i]) ret[j++] = values[i];
125    }
126    ret.length = j;
127    this._resolve(ret);
128};
129
130MappingPromiseArray.prototype.preservedValues = function () {
131    return this._preservedValues;
132};
133
134function map(promises, fn, options, _filter) {
135    if (typeof fn !== "function") {
136        return apiRejection("expecting a function but got " + util.classString(fn));
137    }
138
139    var limit = 0;
140    if (options !== undefined) {
141        if (typeof options === "object" && options !== null) {
142            if (typeof options.concurrency !== "number") {
143                return Promise.reject(
144                    new TypeError("'concurrency' must be a number but it is " +
145                                    util.classString(options.concurrency)));
146            }
147            limit = options.concurrency;
148        } else {
149            return Promise.reject(new TypeError(
150                            "options argument must be an object but it is " +
151                             util.classString(options)));
152        }
153    }
154    limit = typeof limit === "number" &&
155        isFinite(limit) && limit >= 1 ? limit : 0;
156    return new MappingPromiseArray(promises, fn, limit, _filter).promise();
157}
158
159Promise.prototype.map = function (fn, options) {
160    return map(this, fn, options, null);
161};
162
163Promise.map = function (promises, fn, options, _filter) {
164    return map(promises, fn, options, _filter);
165};
166
167
168};
169