2f40efd2493529826e35dbf1ebfd968140c9ad97
[aai/esr-gui.git] /
1 "use strict";
2 module.exports = function(Promise,
3                           PromiseArray,
4                           apiRejection,
5                           tryConvertToPromise,
6                           INTERNAL) {
7 var getDomain = Promise._getDomain;
8 var async = require("./async.js");
9 var util = require("./util.js");
10 var tryCatch = util.tryCatch;
11 var errorObj = util.errorObj;
12 var PENDING = {};
13 var EMPTY_ARRAY = [];
14
15 function MappingPromiseArray(promises, fn, limit, _filter) {
16     this.constructor$(promises);
17     this._promise._captureStackTrace();
18     var domain = getDomain();
19     this._callback = domain === null ? fn : domain.bind(fn);
20     this._preservedValues = _filter === INTERNAL
21         ? new Array(this.length())
22         : null;
23     this._limit = limit;
24     this._inFlight = 0;
25     this._queue = limit >= 1 ? [] : EMPTY_ARRAY;
26     async.invoke(init, this, undefined);
27 }
28 util.inherits(MappingPromiseArray, PromiseArray);
29 function init() {this._init$(undefined, -2);}
30
31 MappingPromiseArray.prototype._init = function () {};
32
33 MappingPromiseArray.prototype._promiseFulfilled = function (value, index) {
34     var values = this._values;
35     var length = this.length();
36     var preservedValues = this._preservedValues;
37     var limit = this._limit;
38     if (values[index] === PENDING) {
39         values[index] = value;
40         if (limit >= 1) {
41             this._inFlight--;
42             this._drainQueue();
43             if (this._isResolved()) return;
44         }
45     } else {
46         if (limit >= 1 && this._inFlight >= limit) {
47             values[index] = value;
48             this._queue.push(index);
49             return;
50         }
51         if (preservedValues !== null) preservedValues[index] = value;
52
53         var callback = this._callback;
54         var receiver = this._promise._boundValue();
55         this._promise._pushContext();
56         var ret = tryCatch(callback).call(receiver, value, index, length);
57         this._promise._popContext();
58         if (ret === errorObj) return this._reject(ret.e);
59
60         var maybePromise = tryConvertToPromise(ret, this._promise);
61         if (maybePromise instanceof Promise) {
62             maybePromise = maybePromise._target();
63             if (maybePromise._isPending()) {
64                 if (limit >= 1) this._inFlight++;
65                 values[index] = PENDING;
66                 return maybePromise._proxyPromiseArray(this, index);
67             } else if (maybePromise._isFulfilled()) {
68                 ret = maybePromise._value();
69             } else {
70                 return this._reject(maybePromise._reason());
71             }
72         }
73         values[index] = ret;
74     }
75     var totalResolved = ++this._totalResolved;
76     if (totalResolved >= length) {
77         if (preservedValues !== null) {
78             this._filter(values, preservedValues);
79         } else {
80             this._resolve(values);
81         }
82
83     }
84 };
85
86 MappingPromiseArray.prototype._drainQueue = function () {
87     var queue = this._queue;
88     var limit = this._limit;
89     var values = this._values;
90     while (queue.length > 0 && this._inFlight < limit) {
91         if (this._isResolved()) return;
92         var index = queue.pop();
93         this._promiseFulfilled(values[index], index);
94     }
95 };
96
97 MappingPromiseArray.prototype._filter = function (booleans, values) {
98     var len = values.length;
99     var ret = new Array(len);
100     var j = 0;
101     for (var i = 0; i < len; ++i) {
102         if (booleans[i]) ret[j++] = values[i];
103     }
104     ret.length = j;
105     this._resolve(ret);
106 };
107
108 MappingPromiseArray.prototype.preservedValues = function () {
109     return this._preservedValues;
110 };
111
112 function map(promises, fn, options, _filter) {
113     var limit = typeof options === "object" && options !== null
114         ? options.concurrency
115         : 0;
116     limit = typeof limit === "number" &&
117         isFinite(limit) && limit >= 1 ? limit : 0;
118     return new MappingPromiseArray(promises, fn, limit, _filter);
119 }
120
121 Promise.prototype.map = function (fn, options) {
122     if (typeof fn !== "function") return apiRejection("fn must be a function\u000a\u000a    See http://goo.gl/916lJJ\u000a");
123
124     return map(this, fn, options, null).promise();
125 };
126
127 Promise.map = function (promises, fn, options, _filter) {
128     if (typeof fn !== "function") return apiRejection("fn must be a function\u000a\u000a    See http://goo.gl/916lJJ\u000a");
129     return map(promises, fn, options, _filter).promise();
130 };
131
132
133 };