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