@qooxdoo/framework 7.8.0 → 7.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Manifest.json +2 -2
- package/lib/compiler/compile-info.json +72 -70
- package/lib/compiler/index.js +2255 -1385
- package/lib/resource/qx/tool/website/build/404.html +3 -25
- package/lib/resource/qx/tool/website/build/about.html +3 -25
- package/lib/resource/qx/tool/website/build/assets/common.js +20 -0
- package/lib/resource/qx/tool/website/build/diagnostics/dependson.html +3 -25
- package/lib/resource/qx/tool/website/build/diagnostics/requiredby.html +3 -22
- package/lib/resource/qx/tool/website/build/index.html +3 -25
- package/lib/resource/qx/tool/website/partials/footer.html +3 -21
- package/lib/resource/qx/tool/website/partials/head.html +0 -1
- package/package.json +2 -1
- package/source/class/qx/Bootstrap.js +6 -3
- package/source/class/qx/Promise.js +93 -6964
- package/source/class/qx/core/Environment.js +1 -0
- package/source/class/qx/data/marshal/Json.js +64 -11
- package/source/class/qx/event/handler/TouchCore.js +3 -1
- package/source/class/qx/lang/Type.js +36 -3
- package/source/class/qx/promise/BluebirdImpl.js +6918 -0
- package/source/class/qx/promise/NativeWrapper.js +738 -0
- package/source/class/qx/test/Promise.js +1145 -22
- package/source/class/qx/test/data/controller/List.js +6 -0
- package/source/class/qx/test/data/marshal/Json.js +29 -0
- package/source/class/qx/test/io/request/Xhr.js +16 -0
- package/source/class/qx/test/lang/Type.js +151 -0
- package/source/class/qx/theme/indigo/ColorDark.js +1 -1
- package/source/class/qx/ui/core/MPlacement.js +18 -7
- package/source/class/qx/ui/table/pane/Scroller.js +1 -1
- package/source/class/qx/util/ConcurrencyLimiter.js +78 -0
- package/source/resource/qx/tool/website/build/404.html +3 -25
- package/source/resource/qx/tool/website/build/about.html +3 -25
- package/source/resource/qx/tool/website/build/assets/common.js +20 -0
- package/source/resource/qx/tool/website/build/diagnostics/dependson.html +3 -25
- package/source/resource/qx/tool/website/build/diagnostics/requiredby.html +3 -22
- package/source/resource/qx/tool/website/build/index.html +3 -25
- package/source/resource/qx/tool/website/partials/footer.html +3 -21
- package/source/resource/qx/tool/website/partials/head.html +0 -1
- package/lib/resource/qx/tool/website/build/assets/bluebird.min.js +0 -4615
- package/lib/resource/qx/tool/website/src/assets/bluebird.min.js +0 -4615
- package/source/resource/qx/tool/website/build/assets/bluebird.min.js +0 -4615
- package/source/resource/qx/tool/website/src/assets/bluebird.min.js +0 -4615
|
@@ -0,0 +1,738 @@
|
|
|
1
|
+
/* ************************************************************************
|
|
2
|
+
|
|
3
|
+
qooxdoo - the new era of web development
|
|
4
|
+
|
|
5
|
+
http://qooxdoo.org
|
|
6
|
+
|
|
7
|
+
Copyright:
|
|
8
|
+
2016 Zenesis Limited, http://www.zenesis.com
|
|
9
|
+
|
|
10
|
+
License:
|
|
11
|
+
MIT: https://opensource.org/licenses/MIT
|
|
12
|
+
See the LICENSE file in the project's top-level directory for details.
|
|
13
|
+
|
|
14
|
+
Authors:
|
|
15
|
+
* John Spackman (john.spackman@zenesis.com)
|
|
16
|
+
* Patryk Malinowski (pmalinowski@vmn.digital)
|
|
17
|
+
|
|
18
|
+
************************************************************************ */
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Wrapper around a native promise, adding some extra helpful methods which are found in Bluebird.js,
|
|
22
|
+
* such as .map, .reduce, .filter, and many more.
|
|
23
|
+
*
|
|
24
|
+
* @ignore(AggregateError)
|
|
25
|
+
*/
|
|
26
|
+
qx.Class.define("qx.promise.NativeWrapper", {
|
|
27
|
+
extend: qx.core.Object,
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @overload
|
|
31
|
+
* @param {(resolve: Function, reject: Function) => void} arg0 The executor for the promise
|
|
32
|
+
*
|
|
33
|
+
* @overload
|
|
34
|
+
* Wraps a native promise in the wrapper class
|
|
35
|
+
* @param {Promise} arg0 A native Promise
|
|
36
|
+
*/
|
|
37
|
+
construct(arg0) {
|
|
38
|
+
super();
|
|
39
|
+
if (typeof arg0 === "function") {
|
|
40
|
+
this.__promise = new Promise(arg0);
|
|
41
|
+
} else if (typeof arg0 === "object" && arg0.constructor === Promise) {
|
|
42
|
+
this.__promise = arg0;
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
members: {
|
|
47
|
+
/**
|
|
48
|
+
* @type {Object} The context that this promise is bound to
|
|
49
|
+
*/
|
|
50
|
+
__context: null,
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Creates a new promise just like this one, but with a context set
|
|
54
|
+
* @see
|
|
55
|
+
* @param {Object} context
|
|
56
|
+
* @returns
|
|
57
|
+
*/
|
|
58
|
+
bind(context) {
|
|
59
|
+
let promise = new qx.promise.NativeWrapper(this.__promise);
|
|
60
|
+
return promise.__setContext(context);
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Same as for Native Promise
|
|
65
|
+
* @returns {qx.promise.NativeWrapper}
|
|
66
|
+
*/
|
|
67
|
+
then(onResolved, onRejected) {
|
|
68
|
+
onResolved = onResolved.bind(this.__context);
|
|
69
|
+
if (onRejected) {
|
|
70
|
+
onRejected = onRejected.bind(this.__context);
|
|
71
|
+
}
|
|
72
|
+
return qx.promise.NativeWrapper.__wrap(
|
|
73
|
+
this.__promise.then(onResolved, onRejected)
|
|
74
|
+
).__setContext(this.__context);
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Same as for Native Promise
|
|
79
|
+
* @returns {qx.promise.NativeWrapper}
|
|
80
|
+
*/
|
|
81
|
+
catch(handler) {
|
|
82
|
+
handler = handler.bind(this.__context);
|
|
83
|
+
return qx.promise.NativeWrapper.__wrap(
|
|
84
|
+
this.__promise.catch(handler)
|
|
85
|
+
).__setContext(this.__context);
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Same as for Native Promise
|
|
90
|
+
* @returns {qx.promise.NativeWrapper}
|
|
91
|
+
*/
|
|
92
|
+
spread(fulfilledHandler) {
|
|
93
|
+
return this.then(values => fulfilledHandler(...values));
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Same as for Native Promise
|
|
98
|
+
* @returns {qx.promise.NativeWrapper}
|
|
99
|
+
*/
|
|
100
|
+
finally(handler) {
|
|
101
|
+
handler = handler.bind(this.__context);
|
|
102
|
+
return qx.promise.NativeWrapper.__wrap(
|
|
103
|
+
this.__promise.finally(handler)
|
|
104
|
+
).__setContext(this.__context);
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Due to the high complexity of implementing this feature, it is not supported in qx.promise.NativeWrapper
|
|
109
|
+
*/
|
|
110
|
+
cancel() {
|
|
111
|
+
throw new Error(
|
|
112
|
+
"qx.promise.NativeWrapper does not support canceling promises"
|
|
113
|
+
);
|
|
114
|
+
},
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Note: Only call when this promise will resolve to an array
|
|
118
|
+
* Same as Promise.all, but passed with the array that this promise resolves to
|
|
119
|
+
* @returns {qx.promise.NativeWrapper}
|
|
120
|
+
*/
|
|
121
|
+
all(...args) {
|
|
122
|
+
return qx.promise.NativeWrapper.all(this, ...args);
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Note: Only call when this promise will resolve to an array
|
|
127
|
+
* Same as Promise.race, but passed with the array that this promise resolves to
|
|
128
|
+
* @returns {qx.promise.NativeWrapper}
|
|
129
|
+
*/
|
|
130
|
+
race() {
|
|
131
|
+
return qx.promise.NativeWrapper.race(this);
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Note: Only call when this promise will resolve to an array
|
|
136
|
+
* Same as Promise.any, but passed with the array that this promise resolves to
|
|
137
|
+
* @returns {qx.promise.NativeWrapper}
|
|
138
|
+
*/
|
|
139
|
+
any() {
|
|
140
|
+
return qx.promise.NativeWrapper.any(this);
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Same as {@link qx.promise.NativeWrapper.some} except that it iterates over the value of this promise, when
|
|
145
|
+
* it is fulfilled; return a promise that is fulfilled as soon as count promises are fulfilled
|
|
146
|
+
* in the array. The fulfillment value is an array with count values in the order they were fulfilled.
|
|
147
|
+
*
|
|
148
|
+
* @param count {Integer}
|
|
149
|
+
* @return {qx.promise.NativeWrapper}
|
|
150
|
+
*/
|
|
151
|
+
some(count) {
|
|
152
|
+
return qx.promise.NativeWrapper.some(this, count);
|
|
153
|
+
},
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Same as {@link qx.promise.NativeWrapper.each} except that it iterates over the value of this promise, when
|
|
157
|
+
* it is fulfilled; iterates over the values with the given <code>iterator</code> function with the signature
|
|
158
|
+
* <code>(value, index, length)</code> where <code>value</code> is the resolved value. Iteration happens
|
|
159
|
+
* serially. If any promise is rejected the returned promise is rejected as well.
|
|
160
|
+
*
|
|
161
|
+
* Resolves to the original array unmodified, this method is meant to be used for side effects. If the iterator
|
|
162
|
+
* function returns a promise or a thenable, then the result of the promise is awaited, before continuing with
|
|
163
|
+
* next iteration.
|
|
164
|
+
*
|
|
165
|
+
* @param iterator {Function} the callback, with <code>(value, index, length)</code>
|
|
166
|
+
* @return {qx.promise.NativeWrapper}
|
|
167
|
+
*/
|
|
168
|
+
each(iterator) {
|
|
169
|
+
return qx.promise.NativeWrapper.each(this, iterator);
|
|
170
|
+
},
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Same as {@link qx.promise.NativeWrapper.filter} except that it iterates over the value of this promise, when it is fulfilled;
|
|
174
|
+
* iterates over all the values into an array and filter the array to another using the given filterer function.
|
|
175
|
+
*
|
|
176
|
+
* @param iterable {Iterable} An iterable object, such as an Array
|
|
177
|
+
* @param iterator {Function} the callback, with <code>(value, index, length)</code>
|
|
178
|
+
* @param options {Object?} options; can be:
|
|
179
|
+
* <code>concurrency</code> max nuber of simultaneous filters, default is <code>Infinity</code>
|
|
180
|
+
* @return {qx.promise.NativeWrapper}
|
|
181
|
+
*/
|
|
182
|
+
filter(iterator, options) {
|
|
183
|
+
return qx.promise.NativeWrapper.filter(this, iterator, options);
|
|
184
|
+
},
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Same as {@link qx.promise.NativeWrapper.map} except that it iterates over the value of this promise, when it is fulfilled;
|
|
188
|
+
* iterates over all the values into an array and map the array to another using the given mapper function.
|
|
189
|
+
*
|
|
190
|
+
* Promises returned by the mapper function are awaited for and the returned promise doesn't fulfill
|
|
191
|
+
* until all mapped promises have fulfilled as well. If any promise in the array is rejected, or
|
|
192
|
+
* any promise returned by the mapper function is rejected, the returned promise is rejected as well.
|
|
193
|
+
*
|
|
194
|
+
* The mapper function for a given item is called as soon as possible, that is, when the promise
|
|
195
|
+
* for that item's index in the input array is fulfilled. This doesn't mean that the result array
|
|
196
|
+
* has items in random order, it means that .map can be used for concurrency coordination unlike
|
|
197
|
+
* .all.
|
|
198
|
+
*
|
|
199
|
+
* @param iterator {Function} the callback, with <code>(value, index, length)</code>
|
|
200
|
+
* @param options {Object?} * A native object with one key: <code>concurrency</code>: max number of simultaneous maps, default is <code>Infinity</code>
|
|
201
|
+
* @return {qx.promise.NativeWrapper}
|
|
202
|
+
*/
|
|
203
|
+
map(iterator, options) {
|
|
204
|
+
return qx.promise.NativeWrapper.map(this, iterator, options);
|
|
205
|
+
},
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Same as {@link qx.promise.NativeWrapper.mapSeries} except that it iterates over the value of this promise, when
|
|
209
|
+
* it is fulfilled; iterates over all the values into an array and iterate over the array serially,
|
|
210
|
+
* in-order.
|
|
211
|
+
*
|
|
212
|
+
* Returns a promise for an array that contains the values returned by the iterator function in their
|
|
213
|
+
* respective positions. The iterator won't be called for an item until its previous item, and the
|
|
214
|
+
* promise returned by the iterator for that item are fulfilled. This results in a mapSeries kind of
|
|
215
|
+
* utility but it can also be used simply as a side effect iterator similar to Array#forEach.
|
|
216
|
+
*
|
|
217
|
+
* If any promise in the input array is rejected or any promise returned by the iterator function is
|
|
218
|
+
* rejected, the result will be rejected as well.
|
|
219
|
+
*
|
|
220
|
+
* @param iterator {Function} the callback, with <code>(value, index, length)</code>
|
|
221
|
+
* @return {qx.promise.NativeWrapper}
|
|
222
|
+
*/
|
|
223
|
+
mapSeries(iterator, options) {
|
|
224
|
+
return qx.promise.NativeWrapper.mapSeries(this, iterator, options);
|
|
225
|
+
},
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Same as {@link qx.promise.NativeWrapper.reduce} except that it iterates over the value of this promise, when
|
|
229
|
+
* it is fulfilled; iterates over all the values in the <code>Iterable</code> into an array and
|
|
230
|
+
* reduce the array to a value using the given reducer function.
|
|
231
|
+
*
|
|
232
|
+
* If the reducer function returns a promise, then the result of the promise is awaited, before
|
|
233
|
+
* continuing with next iteration. If any promise in the array is rejected or a promise returned
|
|
234
|
+
* by the reducer function is rejected, the result is rejected as well.
|
|
235
|
+
*
|
|
236
|
+
* If initialValue is undefined (or a promise that resolves to undefined) and the iterable contains
|
|
237
|
+
* only 1 item, the callback will not be called and the iterable's single item is returned. If the
|
|
238
|
+
* iterable is empty, the callback will not be called and initialValue is returned (which may be
|
|
239
|
+
* undefined).
|
|
240
|
+
*
|
|
241
|
+
* qx.promise.NativeWrapper.reduce will start calling the reducer as soon as possible, this is why you might want to
|
|
242
|
+
* use it over qx.promise.NativeWrapper.all (which awaits for the entire array before you can call Array#reduce on it).
|
|
243
|
+
*
|
|
244
|
+
* @param reducer {Function} the callback, with <code>(value, index, length)</code>
|
|
245
|
+
* @param initialValue {Object?} optional initial value
|
|
246
|
+
* @return {qx.promise.NativeWrapper}
|
|
247
|
+
*/
|
|
248
|
+
reduce(reducer, initialValue) {
|
|
249
|
+
return qx.promise.NativeWrapper.reduce(this, reducer, initialValue);
|
|
250
|
+
},
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
*
|
|
254
|
+
* @param {Object} context
|
|
255
|
+
* @returns {qx.promise.NativeWrapper} this object to support chaining
|
|
256
|
+
*/
|
|
257
|
+
__setContext(context) {
|
|
258
|
+
this.__context = context;
|
|
259
|
+
return this;
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
|
|
263
|
+
statics: {
|
|
264
|
+
/**
|
|
265
|
+
* Wraps a promise in a qx.promise.NativeWrapper
|
|
266
|
+
* @param {Promise} promise
|
|
267
|
+
* @returns
|
|
268
|
+
*/
|
|
269
|
+
__wrap(promise) {
|
|
270
|
+
if (qx.core.Environment.get("qx.debug")) {
|
|
271
|
+
if (promise.constructor !== Promise) {
|
|
272
|
+
throw new Error("Only native promises can be wrapped!");
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return new qx.promise.NativeWrapper(promise);
|
|
277
|
+
},
|
|
278
|
+
/**
|
|
279
|
+
* Returns a Promise object that is resolved with the given value. If the value is a thenable (i.e.
|
|
280
|
+
* has a then method), the returned promise will "follow" that thenable, adopting its eventual
|
|
281
|
+
* state; otherwise the returned promise will be fulfilled with the value. Generally, if you
|
|
282
|
+
* don't know if a value is a promise or not, Promise.resolve(value) it instead and work with
|
|
283
|
+
* the return value as a promise.
|
|
284
|
+
*
|
|
285
|
+
* @param value {Object}
|
|
286
|
+
* @return {qx.promise.NativeWrapper}
|
|
287
|
+
*/
|
|
288
|
+
resolve(value) {
|
|
289
|
+
return qx.promise.NativeWrapper.__wrap(Promise.resolve(value));
|
|
290
|
+
},
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Returns a Promise object that is rejected with the given reason.
|
|
294
|
+
* @param reason {Object?} Reason why this Promise rejected. A warning is generated if not instanceof Error. If undefined, a default Error is used.
|
|
295
|
+
* @return {qx.promise.NativeWrapper}
|
|
296
|
+
*/
|
|
297
|
+
reject(reason) {
|
|
298
|
+
return qx.promise.NativeWrapper.__wrap(Promise.reject(reason));
|
|
299
|
+
},
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Returns a promise that resolves when all of the promises in the object properties have resolved,
|
|
303
|
+
* or rejects with the reason of the first passed promise that rejects. The result of each property
|
|
304
|
+
* is placed back in the object, replacing the promise. Note that non-promise values are untouched.
|
|
305
|
+
*
|
|
306
|
+
* @param value {var} An object
|
|
307
|
+
* @return {qx.promise.NativeWrapper}
|
|
308
|
+
*/
|
|
309
|
+
allOf(value) {
|
|
310
|
+
function action(value) {
|
|
311
|
+
var arr = [];
|
|
312
|
+
var names = [];
|
|
313
|
+
for (var name in value) {
|
|
314
|
+
if (value.hasOwnProperty(name) && qx.Promise.isPromise(value[name])) {
|
|
315
|
+
arr.push(value[name]);
|
|
316
|
+
names.push(name);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return qx.promise.NativeWrapper.all(arr).then(function (arr) {
|
|
320
|
+
arr.forEach(function (item, index) {
|
|
321
|
+
value[names[index]] = item;
|
|
322
|
+
});
|
|
323
|
+
return value;
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
return qx.Promise.isPromise(value) ? value.then(action) : action(value);
|
|
327
|
+
},
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Returns a promise that resolves when all of the promises in the iterable argument have resolved,
|
|
331
|
+
* or rejects with the reason of the first passed promise that rejects. Note that non-promise values
|
|
332
|
+
* are untouched.
|
|
333
|
+
*
|
|
334
|
+
* @param iterable {Iterable} An iterable object, such as an Array
|
|
335
|
+
* @return {qx.promise.NativeWrapper}
|
|
336
|
+
*/
|
|
337
|
+
all(iterable) {
|
|
338
|
+
return qx.promise.NativeWrapper.resolve(iterable).then(iterable =>
|
|
339
|
+
qx.promise.NativeWrapper.__wrap(Promise.all(iterable))
|
|
340
|
+
);
|
|
341
|
+
},
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Returns a promise that resolves or rejects as soon as one of the promises in the iterable resolves
|
|
345
|
+
* or rejects, with the value or reason from that promise.
|
|
346
|
+
* @param iterable {Iterable} An iterable object, such as an Array
|
|
347
|
+
* @return {qx.promise.NativeWrapper}
|
|
348
|
+
*/
|
|
349
|
+
race(iterable) {
|
|
350
|
+
return qx.promise.NativeWrapper.resolve(iterable).then(
|
|
351
|
+
iterableResolved =>
|
|
352
|
+
new qx.promise.NativeWrapper(Promise.race(iterableResolved))
|
|
353
|
+
);
|
|
354
|
+
},
|
|
355
|
+
|
|
356
|
+
/* *********************************************************************************
|
|
357
|
+
*
|
|
358
|
+
* Extension API methods
|
|
359
|
+
*
|
|
360
|
+
*/
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Like Promise.some, with 1 as count. However, if the promise fulfills, the fulfillment value is not an
|
|
364
|
+
* array of 1 but the value directly.
|
|
365
|
+
*
|
|
366
|
+
* @param iterable {Iterable} An iterable object, such as an Array
|
|
367
|
+
* @return {qx.promise.NativeWrapper}
|
|
368
|
+
*/
|
|
369
|
+
any(iterable) {
|
|
370
|
+
return qx.promise.NativeWrapper.resolve(iterable).then(
|
|
371
|
+
iterableResolved =>
|
|
372
|
+
new qx.promise.NativeWrapper(Promise.any(iterableResolved))
|
|
373
|
+
);
|
|
374
|
+
},
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Given an Iterable (arrays are Iterable), or a promise of an Iterable, which produces promises (or a mix
|
|
378
|
+
* of promises and values), iterate over all the values in the Iterable into an array and return a promise
|
|
379
|
+
* that is fulfilled as soon as count promises are fulfilled in the array. The fulfillment value is an
|
|
380
|
+
* array with count values in the order they were fulfilled.
|
|
381
|
+
*
|
|
382
|
+
* @param iterable {Iterable} An iterable object, such as an Array
|
|
383
|
+
* @param count {Integer}
|
|
384
|
+
* @return {qx.promise.NativeWrapper}
|
|
385
|
+
*/
|
|
386
|
+
some(iterable, count) {
|
|
387
|
+
return new qx.promise.NativeWrapper((resolve, reject) => {
|
|
388
|
+
qx.promise.NativeWrapper.resolve(iterable).then(iterable => {
|
|
389
|
+
let resolved = [];
|
|
390
|
+
let rejected = [];
|
|
391
|
+
let minToReject = iterable.length - count + 1;
|
|
392
|
+
|
|
393
|
+
const onResolved = value => {
|
|
394
|
+
if (resolved.length >= count) {
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
resolved.push(value);
|
|
398
|
+
if (resolved.length == count) {
|
|
399
|
+
resolve(resolved);
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
const onRejected = reason => {
|
|
404
|
+
rejected.push(reason);
|
|
405
|
+
if (--minToReject == 0) {
|
|
406
|
+
reject(new AggregateError(rejected));
|
|
407
|
+
}
|
|
408
|
+
};
|
|
409
|
+
iterable.forEach((elem, index) => {
|
|
410
|
+
if (qx.Promise.isPromise(elem)) {
|
|
411
|
+
elem.then(onResolved, onRejected);
|
|
412
|
+
} else {
|
|
413
|
+
onResolved(elem);
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
});
|
|
417
|
+
});
|
|
418
|
+
},
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Iterate over an array, or a promise of an array, which contains promises (or a mix of promises and values)
|
|
422
|
+
* with the given <code>iterator</code> function with the signature <code>(value, index, length)</code> where
|
|
423
|
+
* <code>value</code> is the resolved value of a respective promise in the input array. Iteration happens
|
|
424
|
+
* serially. If any promise in the input array is rejected the returned promise is rejected as well.
|
|
425
|
+
*
|
|
426
|
+
* Resolves to the original array unmodified, this method is meant to be used for side effects. If the iterator
|
|
427
|
+
* function returns a promise or a thenable, then the result of the promise is awaited, before continuing with
|
|
428
|
+
* next iteration.
|
|
429
|
+
*
|
|
430
|
+
* @param iterable {Iterable} An iterable object, such as an Array
|
|
431
|
+
* @param iterator {Function} the callback, with <code>(value, index, length)</code>
|
|
432
|
+
* @return {qx.promise.NativeWrapper}
|
|
433
|
+
*/
|
|
434
|
+
each(iterable, iterator) {
|
|
435
|
+
let f = async () => {
|
|
436
|
+
let iterableValue = await iterable;
|
|
437
|
+
let index = 0;
|
|
438
|
+
|
|
439
|
+
for (let item of iterableValue) {
|
|
440
|
+
let itemResolved = await item;
|
|
441
|
+
await iterator(itemResolved, index++, iterable.length);
|
|
442
|
+
}
|
|
443
|
+
};
|
|
444
|
+
return new qx.promise.NativeWrapper(f());
|
|
445
|
+
},
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Given an Iterable(arrays are Iterable), or a promise of an Iterable, which produces promises (or a mix of
|
|
449
|
+
* promises and values), iterate over all the values in the Iterable into an array and filter the array to
|
|
450
|
+
* another using the given filterer function.
|
|
451
|
+
*
|
|
452
|
+
* It is essentially an efficient shortcut for doing a .map and then Array#filter:
|
|
453
|
+
* <pre>
|
|
454
|
+
* qx.promise.NativeWrapper.map(valuesToBeFiltered, function(value, index, length) {
|
|
455
|
+
* return Promise.all([filterer(value, index, length), value]);
|
|
456
|
+
* }).then(function(values) {
|
|
457
|
+
* return values.filter(function(stuff) {
|
|
458
|
+
* return stuff[0] == true
|
|
459
|
+
* }).map(function(stuff) {
|
|
460
|
+
* return stuff[1];
|
|
461
|
+
* });
|
|
462
|
+
* });
|
|
463
|
+
* </pre>
|
|
464
|
+
*
|
|
465
|
+
* @param iterable {Iterable} An iterable object, such as an Array
|
|
466
|
+
* @param iterator {Function} the callback, with <code>(value, index, length)</code>
|
|
467
|
+
* @param options {Object?} Either:
|
|
468
|
+
* A native object with one key: <code>concurrency</code>: max number of simultaneous filters, default is <code>Infinity</code>
|
|
469
|
+
* Or: any other object, in which case this will be the context for the iterator
|
|
470
|
+
* @return {qx.promise.NativeWrapper}
|
|
471
|
+
*/
|
|
472
|
+
filter(iterable, iterator, options) {
|
|
473
|
+
let limiter = new qx.util.ConcurrencyLimiter(options?.concurrency);
|
|
474
|
+
|
|
475
|
+
const doit = async () => {
|
|
476
|
+
let iterableResolved = await iterable;
|
|
477
|
+
let resultsPromises = iterableResolved.map((item, index) =>
|
|
478
|
+
limiter.add(async () => {
|
|
479
|
+
let itemResolved = await item;
|
|
480
|
+
let keep = await iterator(
|
|
481
|
+
itemResolved,
|
|
482
|
+
index,
|
|
483
|
+
iterableResolved.length
|
|
484
|
+
);
|
|
485
|
+
return { keep, val: itemResolved };
|
|
486
|
+
})
|
|
487
|
+
);
|
|
488
|
+
|
|
489
|
+
let values = await qx.promise.NativeWrapper.all(resultsPromises);
|
|
490
|
+
return values.filter(({ keep }) => keep).map(({ val }) => val);
|
|
491
|
+
};
|
|
492
|
+
|
|
493
|
+
return new qx.promise.NativeWrapper(doit());
|
|
494
|
+
},
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* Given an <code>Iterable</code> (arrays are <code>Iterable</code>), or a promise of an
|
|
498
|
+
* <code>Iterable</code>, which produces promises (or a mix of promises and values), iterate over
|
|
499
|
+
* all the values in the <code>Iterable</code> into an array and map the array to another using
|
|
500
|
+
* the given mapper function.
|
|
501
|
+
*
|
|
502
|
+
* Promises returned by the mapper function are awaited for and the returned promise doesn't fulfill
|
|
503
|
+
* until all mapped promises have fulfilled as well. If any promise in the array is rejected, or
|
|
504
|
+
* any promise returned by the mapper function is rejected, the returned promise is rejected as well.
|
|
505
|
+
*
|
|
506
|
+
* The mapper function for a given item is called as soon as possible, that is, when the promise
|
|
507
|
+
* for that item's index in the input array is fulfilled. This doesn't mean that the result array
|
|
508
|
+
* has items in random order, it means that .map can be used for concurrency coordination unlike
|
|
509
|
+
* .all.
|
|
510
|
+
*
|
|
511
|
+
* A common use of Promise.map is to replace the .push+Promise.all boilerplate:
|
|
512
|
+
*
|
|
513
|
+
* <pre>
|
|
514
|
+
* var promises = [];
|
|
515
|
+
* for (var i = 0; i < fileNames.length; ++i) {
|
|
516
|
+
* promises.push(fs.readFileAsync(fileNames[i]));
|
|
517
|
+
* }
|
|
518
|
+
* qx.promise.NativeWrapper.all(promises).then(function() {
|
|
519
|
+
* console.log("done");
|
|
520
|
+
* });
|
|
521
|
+
*
|
|
522
|
+
* // Using Promise.map:
|
|
523
|
+
* qx.promise.NativeWrapper.map(fileNames, function(fileName) {
|
|
524
|
+
* // Promise.map awaits for returned promises as well.
|
|
525
|
+
* return fs.readFileAsync(fileName);
|
|
526
|
+
* }).then(function() {
|
|
527
|
+
* console.log("done");
|
|
528
|
+
* });
|
|
529
|
+
* </pre>
|
|
530
|
+
*
|
|
531
|
+
* @param iterable {Iterable} An iterable object, such as an Array
|
|
532
|
+
* @param iterator {Function} the callback, with <code>(value, index, length)</code>
|
|
533
|
+
* @param options {Object?} * A native object with one key: <code>concurrency</code>: max number of simultaneous maps, default is <code>Infinity</code>
|
|
534
|
+
* @return {qx.promise.NativeWrapper}
|
|
535
|
+
*/
|
|
536
|
+
map(iterable, iterator, options) {
|
|
537
|
+
return qx.promise.NativeWrapper.resolve(iterable).then(iterable => {
|
|
538
|
+
let limiter = new qx.util.ConcurrencyLimiter(options?.concurrency);
|
|
539
|
+
|
|
540
|
+
let resultsPromises = iterable.map((item, index) =>
|
|
541
|
+
limiter.add(async () => {
|
|
542
|
+
let itemResolved = await item;
|
|
543
|
+
let result = await iterator(itemResolved, index, iterable.length);
|
|
544
|
+
return result;
|
|
545
|
+
})
|
|
546
|
+
);
|
|
547
|
+
|
|
548
|
+
return qx.promise.NativeWrapper.all(resultsPromises);
|
|
549
|
+
});
|
|
550
|
+
},
|
|
551
|
+
|
|
552
|
+
/**
|
|
553
|
+
* Given an <code>Iterable</code>(arrays are <code>Iterable</code>), or a promise of an
|
|
554
|
+
* <code>Iterable</code>, which produces promises (or a mix of promises and values), iterate over
|
|
555
|
+
* all the values in the <code>Iterable</code> into an array and iterate over the array serially,
|
|
556
|
+
* in-order.
|
|
557
|
+
*
|
|
558
|
+
* Returns a promise for an array that contains the values returned by the iterator function in their
|
|
559
|
+
* respective positions. The iterator won't be called for an item until its previous item, and the
|
|
560
|
+
* promise returned by the iterator for that item are fulfilled. This results in a mapSeries kind of
|
|
561
|
+
* utility but it can also be used simply as a side effect iterator similar to Array#forEach.
|
|
562
|
+
*
|
|
563
|
+
* If any promise in the input array is rejected or any promise returned by the iterator function is
|
|
564
|
+
* rejected, the result will be rejected as well.
|
|
565
|
+
*
|
|
566
|
+
* Example where .mapSeries(the instance method) is used for iterating with side effects:
|
|
567
|
+
*
|
|
568
|
+
* <pre>
|
|
569
|
+
* // Source: http://jakearchibald.com/2014/es7-async-functions/
|
|
570
|
+
* function loadStory() {
|
|
571
|
+
* return getJSON('story.json')
|
|
572
|
+
* .then(function(story) {
|
|
573
|
+
* addHtmlToPage(story.heading);
|
|
574
|
+
* return story.chapterURLs.map(getJSON);
|
|
575
|
+
* })
|
|
576
|
+
* .mapSeries(function(chapter) { addHtmlToPage(chapter.html); })
|
|
577
|
+
* .then(function() { addTextToPage("All done"); })
|
|
578
|
+
* .catch(function(err) { addTextToPage("Argh, broken: " + err.message); })
|
|
579
|
+
* .then(function() { document.querySelector('.spinner').style.display = 'none'; });
|
|
580
|
+
* }
|
|
581
|
+
* </pre>
|
|
582
|
+
*
|
|
583
|
+
* @param iterable {Iterable} An iterable object, such as an Array
|
|
584
|
+
* @param iterator {Function} the callback, with <code>(value, index, length)</code>
|
|
585
|
+
* @return {qx.promise.NativeWrapper}
|
|
586
|
+
*/
|
|
587
|
+
mapSeries(iterable, iterator) {
|
|
588
|
+
return new qx.promise.NativeWrapper(async (resolve, reject) => {
|
|
589
|
+
let failed = false;
|
|
590
|
+
const fail = reason => {
|
|
591
|
+
if (!failed) {
|
|
592
|
+
failed = true;
|
|
593
|
+
reject(reason);
|
|
594
|
+
}
|
|
595
|
+
};
|
|
596
|
+
|
|
597
|
+
//We must handle the rejections of promises ASAP
|
|
598
|
+
//to prevent unhandled promise rejections
|
|
599
|
+
qx.promise.NativeWrapper.all(iterable).catch(fail);
|
|
600
|
+
|
|
601
|
+
let result = [];
|
|
602
|
+
|
|
603
|
+
iterable = await iterable;
|
|
604
|
+
|
|
605
|
+
try {
|
|
606
|
+
let index = 0;
|
|
607
|
+
for (let promise of iterable) {
|
|
608
|
+
let value = await promise;
|
|
609
|
+
let mapped = await iterator(value, index++, iterable.length);
|
|
610
|
+
result.push(mapped);
|
|
611
|
+
}
|
|
612
|
+
} catch (ex) {
|
|
613
|
+
fail(ex);
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
resolve(result);
|
|
617
|
+
});
|
|
618
|
+
},
|
|
619
|
+
|
|
620
|
+
/**
|
|
621
|
+
* Given an <code>Iterable</code> (arrays are <code>Iterable</code>), or a promise of an
|
|
622
|
+
* <code>Iterable</code>, which produces promises (or a mix of promises and values), iterate
|
|
623
|
+
* over all the values in the <code>Iterable</code> into an array and reduce the array to a
|
|
624
|
+
* value using the given reducer function.
|
|
625
|
+
*
|
|
626
|
+
* If the reducer function returns a promise, then the result of the promise is awaited, before
|
|
627
|
+
* continuing with next iteration. If any promise in the array is rejected or a promise returned
|
|
628
|
+
* by the reducer function is rejected, the result is rejected as well.
|
|
629
|
+
*
|
|
630
|
+
* Read given files sequentially while summing their contents as an integer. Each file contains
|
|
631
|
+
* just the text 10.
|
|
632
|
+
*
|
|
633
|
+
* <pre>
|
|
634
|
+
* qx.promise.NativeWrapper.reduce(["file1.txt", "file2.txt", "file3.txt"], function(total, fileName) {
|
|
635
|
+
* return fs.readFileAsync(fileName, "utf8").then(function(contents) {
|
|
636
|
+
* return total + parseInt(contents, 10);
|
|
637
|
+
* });
|
|
638
|
+
* }, 0).then(function(total) {
|
|
639
|
+
* //Total is 30
|
|
640
|
+
* });
|
|
641
|
+
* </pre>
|
|
642
|
+
*
|
|
643
|
+
* If initialValue is undefined (or a promise that resolves to undefined) and the iterable contains
|
|
644
|
+
* only 1 item, the callback will not be called and the iterable's single item is returned. If the
|
|
645
|
+
* iterable is empty, the callback will not be called and initialValue is returned (which may be
|
|
646
|
+
* undefined).
|
|
647
|
+
*
|
|
648
|
+
* Promise.reduce will start calling the reducer as soon as possible, this is why you might want to
|
|
649
|
+
* use it over Promise.all (which awaits for the entire array before you can call Array#reduce on it).
|
|
650
|
+
*
|
|
651
|
+
* @param iterable {Iterable} An iterable object, such as an Array
|
|
652
|
+
* @param reducer {Function} the callback, with <code>(value, index, length)</code>
|
|
653
|
+
* @param initialValue {Object?} optional initial value
|
|
654
|
+
* @return {qx.promise.NativeWrapper}
|
|
655
|
+
*/
|
|
656
|
+
reduce(iterable, reducer, initialValue) {
|
|
657
|
+
return new qx.promise.NativeWrapper(async (resolve, reject) => {
|
|
658
|
+
let failed = false;
|
|
659
|
+
function fail(reason) {
|
|
660
|
+
if (!failed) {
|
|
661
|
+
failed = true;
|
|
662
|
+
reject(reason);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
try {
|
|
667
|
+
let iterableResolved = await iterable;
|
|
668
|
+
|
|
669
|
+
//We must handle the rejections of promises ASAP
|
|
670
|
+
//to prevent unhandled promise rejections
|
|
671
|
+
iterableResolved.forEach((item, index) => {
|
|
672
|
+
if (qx.Promise.isPromise(item)) {
|
|
673
|
+
item.catch(fail);
|
|
674
|
+
}
|
|
675
|
+
});
|
|
676
|
+
|
|
677
|
+
let accum = initialValue;
|
|
678
|
+
let index = 0;
|
|
679
|
+
for (let promise of iterableResolved) {
|
|
680
|
+
let data = await promise;
|
|
681
|
+
accum = await reducer(accum, data, index, iterableResolved.length);
|
|
682
|
+
index++;
|
|
683
|
+
}
|
|
684
|
+
resolve(accum);
|
|
685
|
+
} catch (ex) {
|
|
686
|
+
fail(ex);
|
|
687
|
+
}
|
|
688
|
+
});
|
|
689
|
+
},
|
|
690
|
+
|
|
691
|
+
/**
|
|
692
|
+
* Returns a new function that wraps the given function fn. The new function will always return a promise that is
|
|
693
|
+
* fulfilled with the original functions return values or rejected with thrown exceptions from the original function.
|
|
694
|
+
* @param cb {Function}
|
|
695
|
+
* @return {Function}
|
|
696
|
+
*/
|
|
697
|
+
method(cb) {
|
|
698
|
+
return (...args) =>
|
|
699
|
+
new qx.promise.NativeWrapper(resolve =>
|
|
700
|
+
resolve(cb.call(this.__context, ...args))
|
|
701
|
+
);
|
|
702
|
+
},
|
|
703
|
+
|
|
704
|
+
/**
|
|
705
|
+
* Like .all but for object properties or Maps* entries instead of iterated values. Returns a promise that
|
|
706
|
+
* is fulfilled when all the properties of the object or the Map's' values** are fulfilled. The promise's
|
|
707
|
+
* fulfillment value is an object or a Map with fulfillment values at respective keys to the original object
|
|
708
|
+
* or a Map. If any promise in the object or Map rejects, the returned promise is rejected with the rejection
|
|
709
|
+
* reason.
|
|
710
|
+
*
|
|
711
|
+
* If object is a trusted Promise, then it will be treated as a promise for object rather than for its
|
|
712
|
+
* properties. All other objects (except Maps) are treated for their properties as is returned by
|
|
713
|
+
* Object.keys - the object's own enumerable properties.
|
|
714
|
+
*
|
|
715
|
+
* @param input {Object} An Object
|
|
716
|
+
* @return {qx.promise.NativeWrapper}
|
|
717
|
+
*/
|
|
718
|
+
props(input) {
|
|
719
|
+
return qx.promise.NativeWrapper.resolve(input).then(input => {
|
|
720
|
+
let entries = Object.entries(input);
|
|
721
|
+
let promises = entries.map(
|
|
722
|
+
entry =>
|
|
723
|
+
new qx.promise.NativeWrapper(async resolve => {
|
|
724
|
+
const value = await entry[1];
|
|
725
|
+
resolve([entry[0], value]);
|
|
726
|
+
})
|
|
727
|
+
);
|
|
728
|
+
return qx.promise.NativeWrapper.all(promises).then(values => {
|
|
729
|
+
let result = {};
|
|
730
|
+
values.forEach(entry => {
|
|
731
|
+
result[entry[0]] = entry[1];
|
|
732
|
+
});
|
|
733
|
+
return result;
|
|
734
|
+
});
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
});
|