|
1 | 1 | "use strict"; |
2 | | -module.exports = function( |
3 | | - Promise, Promise$_CreatePromiseArray, PromiseArray, apiRejection) { |
| 2 | +module.exports = function(Promise, PromiseArray, INTERNAL, apiRejection) { |
4 | 3 |
|
5 | 4 | var ASSERT = require("./assert.js"); |
| 5 | + var all = Promise.all; |
| 6 | + var util = require("./util.js"); |
| 7 | + var canAttach = require("./errors.js").canAttach; |
| 8 | + var isArray = util.isArray; |
| 9 | + var _cast = Promise._cast; |
6 | 10 |
|
7 | | - function Promise$_mapper(values) { |
8 | | - var fn = this; |
9 | | - var receiver = void 0; |
10 | | - |
11 | | - if (typeof fn !== "function") { |
12 | | - receiver = fn.receiver; |
13 | | - fn = fn.fn; |
14 | | - } |
15 | | - ASSERT(typeof fn === "function"); |
16 | | - var shouldDefer = false; |
17 | | - |
18 | | - var ret = new Array(values.length); |
19 | | - |
20 | | - if (receiver === void 0) { |
21 | | - for (var i = 0, len = values.length; i < len; ++i) { |
22 | | - var value = fn(values[i], i, len); |
23 | | - if (!shouldDefer) { |
24 | | - var maybePromise = Promise._cast(value, |
25 | | - Promise$_mapper, void 0); |
26 | | - if (maybePromise instanceof Promise) { |
27 | | - if (maybePromise.isFulfilled()) { |
28 | | - ret[i] = maybePromise._settledValue; |
29 | | - continue; |
30 | | - } |
31 | | - else { |
32 | | - shouldDefer = true; |
33 | | - } |
34 | | - value = maybePromise; |
35 | | - } |
36 | | - } |
37 | | - ret[i] = value; |
38 | | - } |
39 | | - } |
40 | | - else { |
41 | | - for (var i = 0, len = values.length; i < len; ++i) { |
42 | | - var value = fn.call(receiver, values[i], i, len); |
43 | | - if (!shouldDefer) { |
44 | | - var maybePromise = Promise._cast(value, |
45 | | - Promise$_mapper, void 0); |
46 | | - if (maybePromise instanceof Promise) { |
47 | | - if (maybePromise.isFulfilled()) { |
48 | | - ret[i] = maybePromise._settledValue; |
49 | | - continue; |
50 | | - } |
51 | | - else { |
52 | | - shouldDefer = true; |
53 | | - } |
54 | | - value = maybePromise; |
55 | | - } |
56 | | - } |
57 | | - ret[i] = value; |
58 | | - } |
59 | | - } |
60 | | - return shouldDefer |
61 | | - ? Promise$_CreatePromiseArray(ret, PromiseArray, |
62 | | - Promise$_mapper, void 0).promise() |
63 | | - : ret; |
| 11 | + function unpack(values) { |
| 12 | + ASSERT(this.length === 4); |
| 13 | + return Promise$_Map(values, this[0], this[1], this[2], this[3]); |
64 | 14 | } |
65 | 15 |
|
66 | 16 | function Promise$_Map(promises, fn, useBound, caller, ref) { |
67 | 17 | if (typeof fn !== "function") { |
68 | 18 | return apiRejection(NOT_FUNCTION_ERROR); |
69 | 19 | } |
70 | 20 |
|
71 | | - if (useBound === USE_BOUND && promises._isBound()) { |
72 | | - fn = { |
73 | | - fn: fn, |
74 | | - receiver: promises._boundTo |
75 | | - }; |
| 21 | + var receiver = void 0; |
| 22 | + if (useBound === USE_BOUND) { |
| 23 | + if (promises._isBound()) { |
| 24 | + receiver = promises._boundTo; |
| 25 | + } |
| 26 | + } |
| 27 | + else if (useBound !== DONT_USE_BOUND) { |
| 28 | + receiver = useBound; |
76 | 29 | } |
77 | 30 |
|
78 | | - var ret = Promise$_CreatePromiseArray( |
79 | | - promises, |
80 | | - PromiseArray, |
81 | | - caller, |
82 | | - useBound === USE_BOUND && promises._isBound() |
83 | | - ? promises._boundTo |
84 | | - : void 0 |
85 | | - ).promise(); |
86 | | - |
87 | | - if (ref !== void 0) { |
88 | | - ref.ref = ret; |
| 31 | + var shouldUnwrapItems = ref !== void 0; |
| 32 | + if (shouldUnwrapItems) ref.ref = promises; |
| 33 | + |
| 34 | + if (promises instanceof Promise) { |
| 35 | + return promises._then(unpack, void 0, void 0, |
| 36 | + [fn, receiver, caller, ref], void 0, Promise$_Map); |
| 37 | + } |
| 38 | + else if (!isArray(promises)) { |
| 39 | + return apiRejection(COLLECTION_ERROR); |
89 | 40 | } |
90 | 41 |
|
91 | | - return ret._then( |
92 | | - Promise$_mapper, |
93 | | - void 0, |
94 | | - void 0, |
95 | | - fn, |
96 | | - void 0, |
97 | | - caller |
98 | | - ); |
| 42 | + var promise = new Promise(INTERNAL); |
| 43 | + if (receiver !== void 0) promise._setBoundTo(receiver); |
| 44 | + promise._setTrace(caller, void 0); |
| 45 | + |
| 46 | + var mapping = new Mapping(promise, |
| 47 | + fn, |
| 48 | + promises, |
| 49 | + receiver, |
| 50 | + shouldUnwrapItems); |
| 51 | + mapping.init(); |
| 52 | + return promise; |
99 | 53 | } |
100 | 54 |
|
| 55 | + var pending = {}; |
| 56 | + function Mapping(promise, callback, items, receiver, shouldUnwrapItems) { |
| 57 | + this.shouldUnwrapItems = shouldUnwrapItems; |
| 58 | + this.index = 0; |
| 59 | + this.items = items; |
| 60 | + this.callback = callback; |
| 61 | + this.receiver = receiver; |
| 62 | + this.promise = promise; |
| 63 | + this.result = new Array(items.length); |
| 64 | + } |
| 65 | + util.inherits(Mapping, PromiseArray); |
| 66 | + |
| 67 | + Mapping.prototype.init = function Mapping$init() { |
| 68 | + var items = this.items; |
| 69 | + var len = items.length; |
| 70 | + var result = this.result; |
| 71 | + var isRejected = false; |
| 72 | + for (var i = 0; i < len; ++i) { |
| 73 | + var maybePromise = _cast(items[i], void 0, void 0); |
| 74 | + if (maybePromise instanceof Promise) { |
| 75 | + if (maybePromise.isPending()) { |
| 76 | + result[i] = pending; |
| 77 | + maybePromise._proxyPromiseArray(this, i); |
| 78 | + } |
| 79 | + else if (maybePromise.isFulfilled()) { |
| 80 | + result[i] = maybePromise.value(); |
| 81 | + } |
| 82 | + else { |
| 83 | + maybePromise._unsetRejectionIsUnhandled(); |
| 84 | + if (!isRejected) { |
| 85 | + this.reject(maybePromise.reason()); |
| 86 | + isRejected = true; |
| 87 | + } |
| 88 | + } |
| 89 | + } |
| 90 | + else { |
| 91 | + result[i] = maybePromise; |
| 92 | + } |
| 93 | + } |
| 94 | + if (!isRejected) this.iterate(); |
| 95 | + }; |
| 96 | + |
| 97 | + Mapping.prototype.isResolved = function Mapping$isResolved() { |
| 98 | + return this.promise === null; |
| 99 | + }; |
| 100 | + |
| 101 | + Mapping.prototype._promiseProgressed = |
| 102 | + function Mapping$_promiseProgressed(value) { |
| 103 | + if (this.isResolved()) return; |
| 104 | + this.promise._progress(value); |
| 105 | + }; |
| 106 | + |
| 107 | + Mapping.prototype._promiseFulfilled = |
| 108 | + function Mapping$_promiseFulfilled(value, index) { |
| 109 | + if (this.isResolved()) return; |
| 110 | + this.result[index] = value; |
| 111 | + if (this.shouldUnwrapItems) this.items[index] = value; |
| 112 | + if (this.index === index) this.iterate(); |
| 113 | + }; |
| 114 | + |
| 115 | + Mapping.prototype._promiseRejected = |
| 116 | + function Mapping$_promiseRejected(reason) { |
| 117 | + this.reject(reason); |
| 118 | + }; |
| 119 | + |
| 120 | + Mapping.prototype.reject = function Mapping$reject(reason) { |
| 121 | + if (this.isResolved()) return; |
| 122 | + var trace = canAttach(reason) ? reason : new Error(reason + ""); |
| 123 | + this.promise._attachExtraTrace(trace); |
| 124 | + this.promise._reject(reason, trace); |
| 125 | + }; |
| 126 | + |
| 127 | + Mapping.prototype.iterate = function Mapping$iterate() { |
| 128 | + var i = this.index; |
| 129 | + var items = this.items; |
| 130 | + var result = this.result; |
| 131 | + var len = items.length; |
| 132 | + var result = this.result; |
| 133 | + var receiver = this.receiver; |
| 134 | + var callback = this.callback; |
| 135 | + |
| 136 | + for (; i < len; ++i) { |
| 137 | + var value = result[i]; |
| 138 | + if (value === pending) { |
| 139 | + this.index = i; |
| 140 | + return; |
| 141 | + } |
| 142 | + try { result[i] = callback.call(receiver, value, i, len); } |
| 143 | + catch (e) { return this.reject(e); } |
| 144 | + } |
| 145 | + this.promise._follow(all(result)); |
| 146 | + this.items = this.result = this.callback = this.promise = null; |
| 147 | + }; |
| 148 | + |
101 | 149 | Promise.prototype.map = function Promise$map(fn, ref) { |
102 | 150 | return Promise$_Map(this, fn, USE_BOUND, this.map, ref); |
103 | 151 | }; |
|
0 commit comments