ig-types 6.13.6 → 6.14.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/Promise.js +193 -140
- package/README.md +62 -0
- package/package.json +1 -1
package/Promise.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
/**********************************************************************
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
2
|
*
|
|
6
3
|
* This defines the following extensions to Promise:
|
|
7
4
|
*
|
|
8
5
|
* Promise.iter(seq)
|
|
6
|
+
* <promise>.iter()
|
|
9
7
|
* Iterable promise object.
|
|
10
8
|
* Similar to Promise.all(..) but adds basic iterator/generator
|
|
11
9
|
* API and will resolve the items as they are ready (resolved).
|
|
@@ -19,6 +17,11 @@
|
|
|
19
17
|
* Exposes the API to resolve/reject the promise object
|
|
20
18
|
* externally.
|
|
21
19
|
*
|
|
20
|
+
* <promise>.as(obj)
|
|
21
|
+
* Promise proxy.
|
|
22
|
+
* Proxies the methods available from obj to promise value.
|
|
23
|
+
*
|
|
24
|
+
*
|
|
22
25
|
*
|
|
23
26
|
*
|
|
24
27
|
**********************************************/ /* c8 ignore next 2 */
|
|
@@ -28,18 +31,6 @@
|
|
|
28
31
|
|
|
29
32
|
var object = require('ig-object')
|
|
30
33
|
|
|
31
|
-
// XXX required for STOP...
|
|
32
|
-
//var generator = require('./generator')
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
/*********************************************************************/
|
|
36
|
-
|
|
37
|
-
/* XXX not used yet...
|
|
38
|
-
// NOTE: this is used in a similar fashion to Python's StopIteration...
|
|
39
|
-
var STOP =
|
|
40
|
-
module.STOP =
|
|
41
|
-
object.STOP
|
|
42
|
-
//*/
|
|
43
34
|
|
|
44
35
|
|
|
45
36
|
//---------------------------------------------------------------------
|
|
@@ -48,13 +39,57 @@ module.STOP =
|
|
|
48
39
|
// Like Promise.all(..) but adds ability to iterate through results
|
|
49
40
|
// via generators .map(..)/.reduce(..) and friends...
|
|
50
41
|
//
|
|
42
|
+
// NOTE: it would be nice to support throwing STOP (XXX) from the iterable
|
|
43
|
+
// promise but...
|
|
44
|
+
// - this is more complicated than simply using .smap(..) instead
|
|
45
|
+
// of .map(..) because the list can contain async promises...
|
|
46
|
+
// ...would need to wrap each .then(..) call in try-catch and
|
|
47
|
+
// manually handle the stop...
|
|
48
|
+
// ...then there's a question of derivative iterators etc.
|
|
49
|
+
// - another issue here is that the stop would happen in order of
|
|
50
|
+
// execution and not order of elements...
|
|
51
|
+
// XXX though stopping within a single level might be useful...
|
|
52
|
+
// NOTE: the following can not be implemented here:
|
|
53
|
+
// .splice(..) - can't both modify and return
|
|
54
|
+
// a result...
|
|
55
|
+
// .pop() / .shift() - can't modify the promise, use
|
|
56
|
+
// .first() / .last() instead.
|
|
57
|
+
// [Symbol.iterator]() - needs to be sync and we can't
|
|
58
|
+
// know the number of elements to
|
|
59
|
+
// return promises before the whole
|
|
60
|
+
// iterable promise is resolved.
|
|
61
|
+
// NOTE: we are not using async/await here as we need to control the
|
|
62
|
+
// type of promise returned in cases where we know we are returning
|
|
63
|
+
// an array...
|
|
64
|
+
// NOTE: there is no point in implementing a 1:1 version of this that
|
|
65
|
+
// would not support element expansion/contraction as it would only
|
|
66
|
+
// simplify a couple of methods that are 1:1 (like .map(..) and
|
|
67
|
+
// .some(..)) while methods like .filter(..) will throw everything
|
|
68
|
+
// back to the complex IterablePromise...
|
|
69
|
+
//
|
|
70
|
+
// XXX how do we handle errors/rejections???
|
|
71
|
+
//
|
|
72
|
+
|
|
73
|
+
// XXX should these be exported???
|
|
74
|
+
var iterPromiseProxy =
|
|
75
|
+
//module.iterPromiseProxy =
|
|
76
|
+
function(name){
|
|
77
|
+
return function(...args){
|
|
78
|
+
return this.constructor(
|
|
79
|
+
this.then(function(lst){
|
|
80
|
+
return lst[name](...args) })) } }
|
|
81
|
+
var promiseProxy =
|
|
82
|
+
//module.promiseProxy =
|
|
83
|
+
function(name){
|
|
84
|
+
return async function(...args){
|
|
85
|
+
return (await this)[name](...args) } }
|
|
51
86
|
|
|
52
87
|
var IterablePromise =
|
|
53
88
|
module.IterablePromise =
|
|
54
89
|
object.Constructor('IterablePromise', Promise, {
|
|
55
|
-
//
|
|
56
|
-
//
|
|
57
|
-
|
|
90
|
+
// packed array...
|
|
91
|
+
//
|
|
92
|
+
// Holds promise state.
|
|
58
93
|
//
|
|
59
94
|
// Format:
|
|
60
95
|
// [
|
|
@@ -64,16 +99,27 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
64
99
|
// ...
|
|
65
100
|
// ]
|
|
66
101
|
//
|
|
67
|
-
|
|
102
|
+
// This format has several useful features:
|
|
103
|
+
// - concatenating packed list results in a packed list
|
|
104
|
+
// - adding an iterable promise (as-is) into a packed list results
|
|
105
|
+
// in a packed list
|
|
106
|
+
//
|
|
107
|
+
// NOTE: in general iterable promises are implicitly immutable, so
|
|
108
|
+
// it is not recomended to ever edit this inplace...
|
|
109
|
+
// NOTE: we are not isolation any internals to enable users to
|
|
110
|
+
// responsibly extend the code.
|
|
111
|
+
__packed: null,
|
|
68
112
|
|
|
69
|
-
// low-level .
|
|
113
|
+
// low-level .__packed handlers/helpers...
|
|
70
114
|
//
|
|
71
115
|
// NOTE: these can be useful for debugging and extending...
|
|
72
|
-
|
|
116
|
+
//
|
|
117
|
+
// pack and oprionally transform/handle an array (sync)...
|
|
118
|
+
__pack: function(list, handler=undefined){
|
|
73
119
|
var that = this
|
|
74
120
|
// handle iterable promise list...
|
|
75
121
|
if(list instanceof IterablePromise){
|
|
76
|
-
return this.__handle(list.
|
|
122
|
+
return this.__handle(list.__packed, handler) }
|
|
77
123
|
// handle promise list...
|
|
78
124
|
if(list instanceof Promise){
|
|
79
125
|
return list.then(function(list){
|
|
@@ -97,11 +143,12 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
97
143
|
: !handle ?
|
|
98
144
|
elem
|
|
99
145
|
: handler(elem) }) },
|
|
100
|
-
|
|
146
|
+
// transform/handle packed array (sync)...
|
|
147
|
+
__handle: function(list, handler=undefined){
|
|
101
148
|
var that = this
|
|
102
149
|
if(typeof(list) == 'function'){
|
|
103
150
|
handler = list
|
|
104
|
-
list = this.
|
|
151
|
+
list = this.__packed }
|
|
105
152
|
if(!handler){
|
|
106
153
|
return list }
|
|
107
154
|
// handle promise list...
|
|
@@ -121,50 +168,28 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
121
168
|
return elem.flat() })
|
|
122
169
|
: [handler(elem)] })
|
|
123
170
|
.flat() },
|
|
124
|
-
|
|
171
|
+
// unpack array (async)...
|
|
172
|
+
__unpack: async function(list){
|
|
125
173
|
list = list
|
|
126
|
-
?? this.
|
|
174
|
+
?? this.__packed
|
|
127
175
|
// handle promise list...
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
return Promise.all(list)
|
|
134
|
-
.then(function(list){
|
|
135
|
-
return list.flat() }) },
|
|
176
|
+
return list instanceof Promise ?
|
|
177
|
+
this.__unpack(await list)
|
|
178
|
+
// do the work...
|
|
179
|
+
: (await Promise.all(list))
|
|
180
|
+
.flat() },
|
|
136
181
|
|
|
137
182
|
|
|
138
183
|
// iterator methods...
|
|
139
184
|
//
|
|
140
185
|
// These will return a new IterablePromise instance...
|
|
141
186
|
//
|
|
142
|
-
// When called from a resolved promise these will return a new
|
|
143
|
-
// resolved promise with updated values...
|
|
144
|
-
//
|
|
145
|
-
// When called from a rejected promise these will return a rejected
|
|
146
|
-
// with the same reason promise...
|
|
147
|
-
//
|
|
148
|
-
//
|
|
149
187
|
// NOTE: these are different to Array's equivalents in that the handler
|
|
150
188
|
// is called not in the order of the elements but rather in order
|
|
151
189
|
// of promise resolution...
|
|
152
190
|
// NOTE: index of items is unknowable because items can expand and
|
|
153
|
-
// contract depending on
|
|
191
|
+
// contract depending on handlers (e.g. .filter(..) can remove
|
|
154
192
|
// items)...
|
|
155
|
-
// This the following can not be implemented here:
|
|
156
|
-
// .slice(..)
|
|
157
|
-
// .splice(..)
|
|
158
|
-
// .values() / .keys()
|
|
159
|
-
// .at(..)
|
|
160
|
-
// [Symbol.iterator]() - needs to be sync...
|
|
161
|
-
// The followng methods are questionable:
|
|
162
|
-
// .indexOf(..)
|
|
163
|
-
// .includes(..)
|
|
164
|
-
// .some(..) / .every(..)
|
|
165
|
-
// .sort(..)
|
|
166
|
-
//
|
|
167
|
-
// XXX should these support STOP???
|
|
168
193
|
map: function(func){
|
|
169
194
|
return this.constructor(this,
|
|
170
195
|
function(e){
|
|
@@ -186,13 +211,11 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
186
211
|
: _filter(e) }) },
|
|
187
212
|
// NOTE: this does not return an iterable promise as we can't know
|
|
188
213
|
// what the user reduces to...
|
|
189
|
-
// XXX we could look at the initial state though...
|
|
190
214
|
// NOTE: the items can be handled out of order because the nested
|
|
191
|
-
// promises can resolve in any order
|
|
192
|
-
// XXX doc how to go around this...
|
|
215
|
+
// promises can resolve in any order...
|
|
193
216
|
// NOTE: since order of execution can not be guaranteed there is no
|
|
194
|
-
// point in implementing .reduceRight(..)
|
|
195
|
-
//
|
|
217
|
+
// point in implementing .reduceRight(..) in the same way
|
|
218
|
+
// (see below)...
|
|
196
219
|
reduce: function(func, res){
|
|
197
220
|
return this.constructor(this,
|
|
198
221
|
function(e){
|
|
@@ -200,14 +223,7 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
200
223
|
return [] })
|
|
201
224
|
.then(function(){
|
|
202
225
|
return res }) },
|
|
203
|
-
|
|
204
|
-
// adding this.
|
|
205
|
-
reduceRight: function(func, res){
|
|
206
|
-
return this
|
|
207
|
-
.reverse()
|
|
208
|
-
.reduce(...arguments)
|
|
209
|
-
.reverse() },
|
|
210
|
-
//*/
|
|
226
|
+
|
|
211
227
|
flat: function(depth=1){
|
|
212
228
|
return this.constructor(this,
|
|
213
229
|
function(e){
|
|
@@ -219,7 +235,7 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
219
235
|
e
|
|
220
236
|
: [e] }) },
|
|
221
237
|
reverse: function(){
|
|
222
|
-
var lst = this.
|
|
238
|
+
var lst = this.__packed
|
|
223
239
|
return this.constructor(
|
|
224
240
|
lst instanceof Promise ?
|
|
225
241
|
lst.then(function(elems){
|
|
@@ -256,7 +272,7 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
256
272
|
[cur, ...other]
|
|
257
273
|
: other instanceof Promise ?
|
|
258
274
|
[...cur, other]
|
|
259
|
-
: cur
|
|
275
|
+
: [...cur, ...other],
|
|
260
276
|
'raw') },
|
|
261
277
|
push: function(elem){
|
|
262
278
|
return this.concat([elem]) },
|
|
@@ -264,15 +280,69 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
264
280
|
return this.constructor([elem])
|
|
265
281
|
.concat(this) },
|
|
266
282
|
|
|
267
|
-
// XXX do we need these?
|
|
268
|
-
// .pop()
|
|
269
|
-
// .shift()
|
|
270
|
-
// .first() / .last()
|
|
271
|
-
// .at(..)
|
|
272
|
-
// ...would be nice if these could stop everything that's not
|
|
273
|
-
// needed to execute...
|
|
274
|
-
|
|
275
283
|
|
|
284
|
+
// XXX thses need to stop once an element is found so we cant simply
|
|
285
|
+
// use .map(..) or .reduce(..)...
|
|
286
|
+
// XXX .find(func) / .findIndex(func)
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
// proxy methods...
|
|
290
|
+
//
|
|
291
|
+
// These require the whole promise to resolve to trigger.
|
|
292
|
+
//
|
|
293
|
+
// An exception to this would be .at(0)/.first() and .at(-1)/.last()
|
|
294
|
+
// that can get the target element if it's accessible.
|
|
295
|
+
//
|
|
296
|
+
// NOTE: methods that are guaranteed to return an array will return
|
|
297
|
+
// an iterable promise (created with iterPromiseProxy(..))...
|
|
298
|
+
//
|
|
299
|
+
at: async function(i){
|
|
300
|
+
var list = this.__packed
|
|
301
|
+
return ((i != 0 && i != -1)
|
|
302
|
+
|| list instanceof Promise
|
|
303
|
+
|| list.at(i) instanceof Promise) ?
|
|
304
|
+
(await this).at(i)
|
|
305
|
+
// NOTE: we can only reason about first/last explicit elements,
|
|
306
|
+
// anything else is non-deterministic...
|
|
307
|
+
: list.at(i) instanceof Promise ?
|
|
308
|
+
[await list.at(i)].flat().at(i)
|
|
309
|
+
: list.at(i) instanceof Array ?
|
|
310
|
+
list.at(i).at(i)
|
|
311
|
+
: list.at(i) },
|
|
312
|
+
first: function(){
|
|
313
|
+
return this.at(0) },
|
|
314
|
+
last: function(){
|
|
315
|
+
return this.at(-1) },
|
|
316
|
+
|
|
317
|
+
// NOTE: unlike .reduce(..) this needs the parent fully resolved
|
|
318
|
+
// to be able to iterate from the end.
|
|
319
|
+
// XXX ???
|
|
320
|
+
reduceRight: promiseProxy('reduceRight'),
|
|
321
|
+
|
|
322
|
+
// NOTE: there is no way we can do a sync generator returning
|
|
323
|
+
// promises for values because any promise in .__packed makes the
|
|
324
|
+
// value count/index non-deterministic...
|
|
325
|
+
sort: iterPromiseProxy('sort'),
|
|
326
|
+
// XXX we could have a special-case here for .slice()/slice(0, -1)
|
|
327
|
+
// and possibly othets, should we???
|
|
328
|
+
slice: iterPromiseProxy('slice'),
|
|
329
|
+
|
|
330
|
+
entries: iterPromiseProxy('entries'),
|
|
331
|
+
keys: iterPromiseProxy('keys'),
|
|
332
|
+
// XXX we could possibly make this better via .map(..)
|
|
333
|
+
values: iterPromiseProxy('values'),
|
|
334
|
+
|
|
335
|
+
indexOf: promiseProxy('indexOf'),
|
|
336
|
+
lastIndexOf: promiseProxy('lastIndexOf'),
|
|
337
|
+
includes: promiseProxy('includes'),
|
|
338
|
+
|
|
339
|
+
every: promiseProxy('every'),
|
|
340
|
+
// XXX this can be lazy... (???)
|
|
341
|
+
some: promiseProxy('some'),
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
// promise api...
|
|
345
|
+
//
|
|
276
346
|
// Overload .then(..), .catch(..) and .finally(..) to return a plain
|
|
277
347
|
// Promise instnace...
|
|
278
348
|
//
|
|
@@ -298,6 +368,13 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
298
368
|
: p },
|
|
299
369
|
|
|
300
370
|
|
|
371
|
+
// this is defined globally as Promise.prototype.iter(.,)
|
|
372
|
+
//
|
|
373
|
+
// for details see: PromiseMixin(..) below...
|
|
374
|
+
//iter: function(handler=undefined){ ... },
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
// constructor...
|
|
301
378
|
//
|
|
302
379
|
// Promise.iter([ .. ])
|
|
303
380
|
// -> iterable-promise
|
|
@@ -307,20 +384,21 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
307
384
|
//
|
|
308
385
|
//
|
|
309
386
|
// handler(e)
|
|
310
|
-
// -> [value]
|
|
387
|
+
// -> [value, ..]
|
|
311
388
|
// -> []
|
|
389
|
+
// -> <promise>
|
|
312
390
|
//
|
|
313
391
|
//
|
|
314
|
-
// NOTE: element index is unknowable
|
|
392
|
+
// NOTE: element index is unknowable until the full list is expanded
|
|
315
393
|
// as handler(..)'s return value can expand to any number of
|
|
316
394
|
// items...
|
|
317
395
|
// XXX we can make the index a promise, then if the client needs
|
|
318
396
|
// the value they can wait for it...
|
|
319
397
|
//
|
|
320
398
|
//
|
|
321
|
-
//
|
|
399
|
+
// Special cases useful for extending this constructor...
|
|
322
400
|
//
|
|
323
|
-
// Set raw .
|
|
401
|
+
// Set raw .__packed without any pre-processing...
|
|
324
402
|
// Promise.iter([ .. ], 'raw')
|
|
325
403
|
// -> iterable-promise
|
|
326
404
|
//
|
|
@@ -328,46 +406,13 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
328
406
|
// Promise.iter(false)
|
|
329
407
|
// -> iterable-promise
|
|
330
408
|
//
|
|
331
|
-
//
|
|
332
|
-
// XXX if list is an iterator, can we fill this async???
|
|
333
|
-
// XXX iterator/generator as input:
|
|
334
|
-
// - do we unwind here or externally?
|
|
335
|
-
// ...feels like with the generator external unwinding is
|
|
336
|
-
// needed...
|
|
337
|
-
// XXX would be nice to support trowing STOP...
|
|
338
|
-
// - this is more complicated than simply suing .smap(..) instead
|
|
339
|
-
// of .map(..) because the list can contain async promises...
|
|
340
|
-
// ...would need to wrap each .then(..) call in try-catch and
|
|
341
|
-
// manually handle the stop...
|
|
342
|
-
// - another issue here is that the stop would happen in order of
|
|
343
|
-
// execution and not order of elements...
|
|
344
|
-
// XXX DOC:
|
|
345
|
-
// inputs:
|
|
346
|
-
// - Chaining -- list instanceof IterablePromise
|
|
347
|
-
// After all the promises resolve .flat() should
|
|
348
|
-
// turn this into the input list.
|
|
349
|
-
// For this to work we'll need to at least wrap all
|
|
350
|
-
// arrays and promise results in arrays.
|
|
351
|
-
// (currently each value is wrapped)
|
|
352
|
-
// -> __list
|
|
353
|
-
// - promise (value | array)
|
|
354
|
-
// - array of:
|
|
355
|
-
// - array
|
|
356
|
-
// - value
|
|
357
|
-
// - promise (value | array)
|
|
358
|
-
// - New
|
|
359
|
-
// - promise (value | array)
|
|
360
|
-
// - value (non-array)
|
|
361
|
-
// - array of:
|
|
362
|
-
// - value
|
|
363
|
-
// - promise (value)
|
|
364
409
|
__new__: function(_, list, handler){
|
|
365
410
|
// instance...
|
|
366
411
|
var promise
|
|
367
412
|
var obj = Reflect.construct(
|
|
368
413
|
IterablePromise.__proto__,
|
|
369
414
|
[function(resolve, reject){
|
|
370
|
-
// NOTE: this is here for Promise
|
|
415
|
+
// NOTE: this is here for Promise compatibility...
|
|
371
416
|
if(typeof(list) == 'function'){
|
|
372
417
|
return list.call(this, ...arguments) }
|
|
373
418
|
// initial reject...
|
|
@@ -376,17 +421,17 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
376
421
|
promise = {resolve, reject} }],
|
|
377
422
|
IterablePromise)
|
|
378
423
|
|
|
424
|
+
// populate new instance...
|
|
379
425
|
if(promise){
|
|
426
|
+
// handle/pack input data...
|
|
380
427
|
if(handler != 'raw'){
|
|
381
428
|
list = list instanceof IterablePromise ?
|
|
382
|
-
this.__handle(list.
|
|
429
|
+
this.__handle(list.__packed, handler)
|
|
383
430
|
: this.__pack(list, handler) }
|
|
384
|
-
|
|
385
|
-
Object.defineProperty(obj, '__list', {
|
|
431
|
+
Object.defineProperty(obj, '__packed', {
|
|
386
432
|
value: list,
|
|
387
433
|
enumerable: false,
|
|
388
434
|
})
|
|
389
|
-
|
|
390
435
|
// handle promise state...
|
|
391
436
|
this.__unpack(list)
|
|
392
437
|
.then(function(list){
|
|
@@ -446,13 +491,14 @@ object.Constructor('InteractivePromise', Promise, {
|
|
|
446
491
|
// register a handler...
|
|
447
492
|
} else {
|
|
448
493
|
var h = obj == null ?
|
|
449
|
-
// NOTE: we need to get the handlers from
|
|
450
|
-
// unless we are not
|
|
451
|
-
// bootstrap
|
|
452
|
-
//
|
|
453
|
-
//
|
|
454
|
-
//
|
|
455
|
-
//
|
|
494
|
+
// NOTE: we need to get the handlers from
|
|
495
|
+
// .__message_handlers unless we are not
|
|
496
|
+
// fully defined yet, then use the bootstrap
|
|
497
|
+
// container (handlers)...
|
|
498
|
+
// ...since we can call onmessage(..) while
|
|
499
|
+
// the promise is still defined there is no
|
|
500
|
+
// way to .send(..) until it returns a promise
|
|
501
|
+
// object, this races here are highly unlikely...
|
|
456
502
|
handlers
|
|
457
503
|
: (obj.__message_handlers =
|
|
458
504
|
obj.__message_handlers ?? [])
|
|
@@ -539,10 +585,13 @@ object.Constructor('CooperativePromise', Promise, {
|
|
|
539
585
|
var ProxyPromise =
|
|
540
586
|
module.ProxyPromise =
|
|
541
587
|
object.Constructor('ProxyPromise', Promise, {
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
588
|
+
|
|
589
|
+
then: IterablePromise.prototype.then,
|
|
590
|
+
|
|
591
|
+
__new__: function(context, other, nooverride=false){
|
|
592
|
+
var proto = 'prototype' in other ?
|
|
593
|
+
other.prototype
|
|
594
|
+
: other
|
|
546
595
|
var obj = Reflect.construct(
|
|
547
596
|
ProxyPromise.__proto__,
|
|
548
597
|
[function(resolve, reject){
|
|
@@ -553,6 +602,9 @@ object.Constructor('ProxyPromise', Promise, {
|
|
|
553
602
|
// NOTE: we are not using object.deepKeys(..) here as we need
|
|
554
603
|
// the key origin not to trigger property getters...
|
|
555
604
|
var seen = new Set()
|
|
605
|
+
nooverride = nooverride instanceof Array ?
|
|
606
|
+
new Set(nooverride)
|
|
607
|
+
: nooverride
|
|
556
608
|
while(proto != null){
|
|
557
609
|
Object.entries(Object.getOwnPropertyDescriptors(proto))
|
|
558
610
|
.forEach(function([key, value]){
|
|
@@ -567,11 +619,15 @@ object.Constructor('ProxyPromise', Promise, {
|
|
|
567
619
|
&& Object.prototype.run === value.value)
|
|
568
620
|
&& !value.enumerable){
|
|
569
621
|
return }
|
|
622
|
+
// do not override existing methods...
|
|
623
|
+
if(nooverride === true ?
|
|
624
|
+
key in obj
|
|
625
|
+
: nooverride instanceof Set ?
|
|
626
|
+
nooverride.has(key)
|
|
627
|
+
: nooverride){
|
|
628
|
+
return }
|
|
570
629
|
// proxy...
|
|
571
|
-
obj[key] =
|
|
572
|
-
// XXX should we also .catch(..) here???
|
|
573
|
-
return context.then(function(res){
|
|
574
|
-
return res[key](...args) }) } })
|
|
630
|
+
obj[key] = promiseProxy(key) })
|
|
575
631
|
proto = proto.__proto__ }
|
|
576
632
|
return obj },
|
|
577
633
|
})
|
|
@@ -591,14 +647,11 @@ object.Mixin('PromiseMixin', 'soft', {
|
|
|
591
647
|
PromiseMixin(Promise)
|
|
592
648
|
|
|
593
649
|
|
|
594
|
-
// XXX EXPEREMENTAL...
|
|
595
650
|
var PromiseProtoMixin =
|
|
596
651
|
module.PromiseProtoMixin =
|
|
597
652
|
object.Mixin('PromiseProtoMixin', 'soft', {
|
|
598
653
|
as: ProxyPromise,
|
|
599
|
-
|
|
600
|
-
// XXX
|
|
601
|
-
iter: function(handler){
|
|
654
|
+
iter: function(handler=undefined){
|
|
602
655
|
return IterablePromise(this, handler) },
|
|
603
656
|
})
|
|
604
657
|
|
|
@@ -608,4 +661,4 @@ PromiseProtoMixin(Promise.prototype)
|
|
|
608
661
|
|
|
609
662
|
|
|
610
663
|
/**********************************************************************
|
|
611
|
-
* vim:set ts=4 sw=4 :
|
|
664
|
+
* vim:set ts=4 sw=4 nowrap : */ return module })
|
package/README.md
CHANGED
|
@@ -77,6 +77,9 @@ Library of JavaScript type extensions, types and utilities.
|
|
|
77
77
|
- [`<promise-iter>.reverse()`](#promise-iterreverse)
|
|
78
78
|
- [`<promise-iter>.concat(..)`](#promise-iterconcat)
|
|
79
79
|
- [`<promise-iter>.push(..)` / `<promise-iter>.unshift(..)`](#promise-iterpush--promise-iterunshift)
|
|
80
|
+
- [`<promise-iter>.at(..)` / `<promise-iter>.first()` / `<promise-iter>.last()`](#promise-iterat--promise-iterfirst--promise-iterlast)
|
|
81
|
+
- [Array proxy methods returning `<promise-iter>`](#array-proxy-methods-returning-promise-iter)
|
|
82
|
+
- [Array proxy methods returning a `<promise>`](#array-proxy-methods-returning-a-promise)
|
|
80
83
|
- [`<promise-iter>.then(..)` / `<promise-iter>.catch(..)` / `<promise-iter>.finally(..)`](#promise-iterthen--promise-itercatch--promise-iterfinally)
|
|
81
84
|
- [Advanced handler](#advanced-handler)
|
|
82
85
|
- [Promise proxies](#promise-proxies)
|
|
@@ -1508,6 +1511,17 @@ promise, even if the original is resolved.
|
|
|
1508
1511
|
If all values are resolved the `<promise-iter>` will resolve on the next
|
|
1509
1512
|
execution frame.
|
|
1510
1513
|
|
|
1514
|
+
There are two types of iterator methods here, both are transparent but different
|
|
1515
|
+
in how they process values:
|
|
1516
|
+
- *Parallel methods*
|
|
1517
|
+
These handle elements as soon as they are available even if the parent promise
|
|
1518
|
+
is not yet resolved.
|
|
1519
|
+
<!-- XXX list -->
|
|
1520
|
+
- *Proxies*
|
|
1521
|
+
These methods simply wait for the main promise to resolve and then call the
|
|
1522
|
+
appropriate method on the result.
|
|
1523
|
+
<!-- XXX list + mark definitions as "(proxy)" -->
|
|
1524
|
+
|
|
1511
1525
|
<!--
|
|
1512
1526
|
XXX should we support generators as input?
|
|
1513
1527
|
...not sure about the control flow direction here, on one hand the generator
|
|
@@ -1652,6 +1666,54 @@ and [`<array>.unshift(..)`](https://developer.mozilla.org/en-US/docs/Web/JavaScr
|
|
|
1652
1666
|
see them for more info.
|
|
1653
1667
|
|
|
1654
1668
|
|
|
1669
|
+
#### `<promise-iter>.at(..)` / `<promise-iter>.first()` / `<promise-iter>.last()`
|
|
1670
|
+
|
|
1671
|
+
Proxies to the appropriate array methods with a special-case: when getting elements
|
|
1672
|
+
at positions `0` or `-1` (i.e. `.first()` / `.last()`) these _can_ resolve before the
|
|
1673
|
+
parent `<promise-iter>`.
|
|
1674
|
+
|
|
1675
|
+
XXX
|
|
1676
|
+
|
|
1677
|
+
|
|
1678
|
+
#### Array proxy methods returning `<promise-iter>`
|
|
1679
|
+
|
|
1680
|
+
- `<promise-iter>.sort(..)`
|
|
1681
|
+
- `<promise-iter>.slice(..)`
|
|
1682
|
+
- `<promise-iter>.entries()` / `<promise-iter>.keys()` / `<promise-iter>.values()`
|
|
1683
|
+
|
|
1684
|
+
These methods are proxies to the appropriate array methods.
|
|
1685
|
+
|
|
1686
|
+
```bnf
|
|
1687
|
+
<promise-iter>.<method>(..)
|
|
1688
|
+
-> <promise-iter>
|
|
1689
|
+
```
|
|
1690
|
+
|
|
1691
|
+
These methods need the parent `<promise-iter>` to resolve before resolving themselves.
|
|
1692
|
+
|
|
1693
|
+
XXX links...
|
|
1694
|
+
|
|
1695
|
+
|
|
1696
|
+
#### Array proxy methods returning a `<promise>`
|
|
1697
|
+
|
|
1698
|
+
- `<promise-iter>.indexOf(..)`
|
|
1699
|
+
- `<promise-iter>.includes(..)`
|
|
1700
|
+
- `<promise-iter>.every(..)` / `<promise-iter>.some(..)`
|
|
1701
|
+
|
|
1702
|
+
These methods are proxies to the appropriate array methods.
|
|
1703
|
+
|
|
1704
|
+
```bnf
|
|
1705
|
+
<promise-iter>.<method>(..)
|
|
1706
|
+
-> <promise>
|
|
1707
|
+
```
|
|
1708
|
+
|
|
1709
|
+
These methods need the parent `<promise-iter>` to resolve before resolving themselves.
|
|
1710
|
+
|
|
1711
|
+
Since the equivalent array methods do not return iterables these will return a basic
|
|
1712
|
+
(non-iterable) `<promise>`.
|
|
1713
|
+
|
|
1714
|
+
XXX links...
|
|
1715
|
+
|
|
1716
|
+
|
|
1655
1717
|
#### `<promise-iter>.then(..)` / `<promise-iter>.catch(..)` / `<promise-iter>.finally(..)`
|
|
1656
1718
|
|
|
1657
1719
|
An extension to
|