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