ig-types 6.24.16 → 6.24.20
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 +334 -275
- package/package.json +1 -1
- package/runner.js +32 -12
- package/test.js +167 -18
package/Promise.js
CHANGED
|
@@ -34,6 +34,292 @@ var generator = require('./generator')
|
|
|
34
34
|
|
|
35
35
|
|
|
36
36
|
|
|
37
|
+
//---------------------------------------------------------------------
|
|
38
|
+
|
|
39
|
+
// packed format API...
|
|
40
|
+
//
|
|
41
|
+
// This is separate from IterablePromise to enable low-level testing and
|
|
42
|
+
// experimentation.
|
|
43
|
+
//
|
|
44
|
+
// Packed format
|
|
45
|
+
// [
|
|
46
|
+
// <value>,
|
|
47
|
+
//
|
|
48
|
+
// [
|
|
49
|
+
// <value>,
|
|
50
|
+
//
|
|
51
|
+
// <promise( <value> )>,
|
|
52
|
+
//
|
|
53
|
+
// ..
|
|
54
|
+
// ],
|
|
55
|
+
//
|
|
56
|
+
// <promise( <value> )>,
|
|
57
|
+
//
|
|
58
|
+
// <promise( [ <value>, .. ] )>,
|
|
59
|
+
//
|
|
60
|
+
// ..
|
|
61
|
+
// ]
|
|
62
|
+
//
|
|
63
|
+
// <packed> ::=
|
|
64
|
+
// <value>
|
|
65
|
+
// | <packed-array>
|
|
66
|
+
// | <promise( <value> )>
|
|
67
|
+
// | <promise( <packed-array> )>
|
|
68
|
+
//
|
|
69
|
+
// <packed-array> ::=
|
|
70
|
+
// [ <packed-item>, .. ]
|
|
71
|
+
//
|
|
72
|
+
// <packed-item> ::=
|
|
73
|
+
// <value>
|
|
74
|
+
// | [ <nested-value>, .. ]
|
|
75
|
+
// | <promise( <value> )>
|
|
76
|
+
// | <promise( [ <value>, .. ] )>
|
|
77
|
+
//
|
|
78
|
+
// <nested-value> ::=
|
|
79
|
+
// <value>
|
|
80
|
+
// | <promise( <value> )>
|
|
81
|
+
//
|
|
82
|
+
//
|
|
83
|
+
//
|
|
84
|
+
// XXX revise bnf...
|
|
85
|
+
// XXX should this be a container or just a set of function???
|
|
86
|
+
// ...for simplicity I'll keep it a stateless set of functions for
|
|
87
|
+
// now, to avoid yet another layer of indirection -- IterablePromise...
|
|
88
|
+
var packed =
|
|
89
|
+
module.packed =
|
|
90
|
+
{
|
|
91
|
+
//
|
|
92
|
+
// pack(<array>)
|
|
93
|
+
// pack(<promise>)
|
|
94
|
+
// -> <packed>
|
|
95
|
+
//
|
|
96
|
+
// NOTE: when all promises are expanded the packed array can be unpacked
|
|
97
|
+
// by simply calling .flat()
|
|
98
|
+
// NOTE: if 'types/Array' is imported this will support throwing STOP
|
|
99
|
+
// from the handler.
|
|
100
|
+
// Due to the async nature of promises though the way stops are
|
|
101
|
+
// handled may be unpredictable -- the handlers can be run out
|
|
102
|
+
// of order, as the nested promises resolve and thus throwing
|
|
103
|
+
// stop will stop the handlers not yet run and not the next
|
|
104
|
+
// handlers in sequence.
|
|
105
|
+
// XXX does this need onerror(..) ???
|
|
106
|
+
// ...essentially this can make sense only in generator expansion,
|
|
107
|
+
// but not sure if this should be done here as it is sync...
|
|
108
|
+
pack: function(list){
|
|
109
|
+
var that = this
|
|
110
|
+
// list: promise...
|
|
111
|
+
// XXX should we just test for typeof(list.then) == 'function'???
|
|
112
|
+
// XXX should we expand async generators here???
|
|
113
|
+
if(list instanceof Promise
|
|
114
|
+
// list: async promise...
|
|
115
|
+
|| (typeof(list) == 'object'
|
|
116
|
+
&& list.then
|
|
117
|
+
&& Symbol.asyncIterator in list)){
|
|
118
|
+
return list
|
|
119
|
+
.then(this.pack.bind(this)) }
|
|
120
|
+
// list: generator...
|
|
121
|
+
if(typeof(list) == 'object'
|
|
122
|
+
&& !list.map
|
|
123
|
+
&& Symbol.iterator in list){
|
|
124
|
+
list = [...list] }
|
|
125
|
+
/* XXX on one hand this should be here and on the other I'm not
|
|
126
|
+
// sure how are we going to thread handler and onerror to
|
|
127
|
+
// here...
|
|
128
|
+
// list: promise / async-iterator...
|
|
129
|
+
if(typeof(list) == 'object'
|
|
130
|
+
&& Symbol.asyncIterator in list){
|
|
131
|
+
return list
|
|
132
|
+
// XXX
|
|
133
|
+
.iter(handler, onerror)
|
|
134
|
+
.then(function(list){
|
|
135
|
+
return that.pack(list) }) }
|
|
136
|
+
//*/
|
|
137
|
+
// list: non-array / non-iterable...
|
|
138
|
+
if(typeof(list.map) != 'function'){
|
|
139
|
+
list = [list].flat() }
|
|
140
|
+
// list: array...
|
|
141
|
+
return list
|
|
142
|
+
.map(function(elem){
|
|
143
|
+
// XXX should we expand generators here???
|
|
144
|
+
return elem instanceof Array ?
|
|
145
|
+
[elem]
|
|
146
|
+
// XXX should we just test for .then(..)???
|
|
147
|
+
: elem instanceof Promise ?
|
|
148
|
+
elem.then(function(elem){
|
|
149
|
+
return elem instanceof Array ?
|
|
150
|
+
[elem]
|
|
151
|
+
: elem })
|
|
152
|
+
: elem }) },
|
|
153
|
+
//
|
|
154
|
+
// handle(<packed>, <handler>[, <onerror>])
|
|
155
|
+
// -> <packed>
|
|
156
|
+
//
|
|
157
|
+
handle: function(packed, handler, onerror){
|
|
158
|
+
var that = this
|
|
159
|
+
var handlers = [...arguments].slice(1)
|
|
160
|
+
|
|
161
|
+
if(packed instanceof Promise){
|
|
162
|
+
return packed.then(function(packed){
|
|
163
|
+
return that.handle(packed, ...handlers) }) }
|
|
164
|
+
|
|
165
|
+
var handleSTOP = function(err){
|
|
166
|
+
if(err && err === Array.STOP){
|
|
167
|
+
stop = true
|
|
168
|
+
return []
|
|
169
|
+
} else if(err && err instanceof Array.STOP){
|
|
170
|
+
return err.value }
|
|
171
|
+
throw err }
|
|
172
|
+
|
|
173
|
+
var stop = false
|
|
174
|
+
var map = Array.STOP ?
|
|
175
|
+
'smap'
|
|
176
|
+
: 'map'
|
|
177
|
+
return packed
|
|
178
|
+
// NOTE: we do not need to rapack after this because the handlers
|
|
179
|
+
// will get the correct (unpacked) values and it's their
|
|
180
|
+
// responsibility to pack them if needed...
|
|
181
|
+
// NOTE: this removes the need to handle sub-arrays unless they are
|
|
182
|
+
// in a promise...
|
|
183
|
+
.flat()
|
|
184
|
+
[map](
|
|
185
|
+
function(elem){
|
|
186
|
+
return elem instanceof Promise ?
|
|
187
|
+
elem.then(function(elem){
|
|
188
|
+
if(stop){
|
|
189
|
+
return [] }
|
|
190
|
+
try{
|
|
191
|
+
var has_promise = false
|
|
192
|
+
// NOTE: do the same thing handle(..) does
|
|
193
|
+
// but on a single level, without expanding
|
|
194
|
+
// arrays...
|
|
195
|
+
if(elem instanceof Array){
|
|
196
|
+
var res = elem.map(function(elem){
|
|
197
|
+
var res = elem instanceof Promise ?
|
|
198
|
+
elem.then(function(elem){
|
|
199
|
+
try{
|
|
200
|
+
return !stop ?
|
|
201
|
+
handler(elem)
|
|
202
|
+
: []
|
|
203
|
+
} catch(err){
|
|
204
|
+
return handleSTOP(err) } })
|
|
205
|
+
: handler(elem)
|
|
206
|
+
has_promise = has_promise
|
|
207
|
+
|| res instanceof Promise
|
|
208
|
+
return res })
|
|
209
|
+
// non-arrays...
|
|
210
|
+
} else {
|
|
211
|
+
// NOTE: we are wrapping the result in an array to
|
|
212
|
+
// normalize it with the above...
|
|
213
|
+
res = [handler(elem)]
|
|
214
|
+
has_promise = has_promise
|
|
215
|
+
|| res[0] instanceof Promise }
|
|
216
|
+
|
|
217
|
+
// compensate for the outer .flat()...
|
|
218
|
+
// NOTE: at this point res is always an array...
|
|
219
|
+
return has_promise ?
|
|
220
|
+
// NOTE: since we are already in a promise
|
|
221
|
+
// grouping things here is not a big
|
|
222
|
+
// deal, however this is needed to link
|
|
223
|
+
// nested promises with the containing
|
|
224
|
+
// promise...
|
|
225
|
+
Promise.all(res)
|
|
226
|
+
.then(function(res){
|
|
227
|
+
return res.flat() })
|
|
228
|
+
: res.flat()
|
|
229
|
+
} catch(err){
|
|
230
|
+
return handleSTOP(err) } })
|
|
231
|
+
: handler(elem) },
|
|
232
|
+
// onerror...
|
|
233
|
+
function(err){
|
|
234
|
+
stop = true
|
|
235
|
+
typeof(onerror) == 'function'
|
|
236
|
+
&& onerror(err) }) },
|
|
237
|
+
//
|
|
238
|
+
// unpack(<packed>)
|
|
239
|
+
// -> <array>
|
|
240
|
+
//
|
|
241
|
+
unpack: function(packed){
|
|
242
|
+
if(packed instanceof Promise){
|
|
243
|
+
return packed.then(this.unpack.bind(this)) }
|
|
244
|
+
var input = packed
|
|
245
|
+
// NOTE: we expand promises on the first two levels of the packed
|
|
246
|
+
// list and then flatten the result...
|
|
247
|
+
for(var [i, elem] of Object.entries(packed)){
|
|
248
|
+
// expand promises in lists...
|
|
249
|
+
if(elem instanceof Array){
|
|
250
|
+
for(var e of elem){
|
|
251
|
+
if(e instanceof Promise){
|
|
252
|
+
// copy the input (on demand) list as we'll need to
|
|
253
|
+
// modify it...
|
|
254
|
+
packed === input
|
|
255
|
+
&& (packed = packed.slice())
|
|
256
|
+
// NOTE: this will immediately be caught by the
|
|
257
|
+
// Promise condition below...
|
|
258
|
+
elem = packed[i] =
|
|
259
|
+
Promise.all(elem)
|
|
260
|
+
break } } }
|
|
261
|
+
// expand promises...
|
|
262
|
+
if(elem instanceof Promise){
|
|
263
|
+
return Promise.all(packed)
|
|
264
|
+
.then(this.unpack.bind(this)) } }
|
|
265
|
+
// the list is expanded here...
|
|
266
|
+
return packed.flat() },
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
271
|
+
|
|
272
|
+
//
|
|
273
|
+
// itemResolved(<list>, <onupdate>[, <ondone>])
|
|
274
|
+
// itemResolved(<list>, <options>)
|
|
275
|
+
// -> <list>
|
|
276
|
+
//
|
|
277
|
+
// <onupdate>(<elem>, <index>, <list>)
|
|
278
|
+
//
|
|
279
|
+
// <ondone>(<list>)
|
|
280
|
+
//
|
|
281
|
+
// options format:
|
|
282
|
+
// {
|
|
283
|
+
// onupdate: <func>,
|
|
284
|
+
//
|
|
285
|
+
// // optional
|
|
286
|
+
// ondone: <func>,
|
|
287
|
+
// }
|
|
288
|
+
//
|
|
289
|
+
// XXX rename to Promise.each(..) or Promise.eachPromise(..) ???
|
|
290
|
+
var itemResolved =
|
|
291
|
+
module.itemResolved =
|
|
292
|
+
function(list, onupdate, ondone){
|
|
293
|
+
if(typeof(onupdate) != 'function'){
|
|
294
|
+
var {onupdate, ondone} = onupdate }
|
|
295
|
+
typeof(ondone) == 'function'
|
|
296
|
+
&& Promise.all(list)
|
|
297
|
+
.then(ondone)
|
|
298
|
+
for(let [i, elem] of Object.entries(list)){
|
|
299
|
+
if(elem instanceof Promise){
|
|
300
|
+
elem.then(function(elem){
|
|
301
|
+
onupdate(elem, i, list) }) } }
|
|
302
|
+
return list }
|
|
303
|
+
|
|
304
|
+
// Like itemResolved(..) but both onupdate and ondone are optional...
|
|
305
|
+
//
|
|
306
|
+
// XXX do not modify the array after this is called and until ondone(..) is called...
|
|
307
|
+
// XXX should this know how to expand things???
|
|
308
|
+
var selfResolve =
|
|
309
|
+
module.selfResolve =
|
|
310
|
+
function(list, onupdate, ondone){
|
|
311
|
+
if(onupdate
|
|
312
|
+
&& typeof(onupdate) != 'function'){
|
|
313
|
+
var {onupdate, ondone} = onupdate }
|
|
314
|
+
return itemResolved(list,
|
|
315
|
+
function(elem, i, list){
|
|
316
|
+
list[i] = elem
|
|
317
|
+
typeof(onupdate) == 'function'
|
|
318
|
+
&& onupdate(elem, i, list) },
|
|
319
|
+
ondone) }
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
|
|
37
323
|
//---------------------------------------------------------------------
|
|
38
324
|
// Iterable promise...
|
|
39
325
|
//
|
|
@@ -63,6 +349,9 @@ var generator = require('./generator')
|
|
|
63
349
|
// XXX add support for async generators...
|
|
64
350
|
//
|
|
65
351
|
|
|
352
|
+
var EMPTY = {doc: 'empty placeholder'}
|
|
353
|
+
|
|
354
|
+
|
|
66
355
|
var iterPromiseProxy =
|
|
67
356
|
module.iterPromiseProxy =
|
|
68
357
|
function(name){
|
|
@@ -114,284 +403,45 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
114
403
|
// NOTE: these can be useful for debugging and extending...
|
|
115
404
|
//
|
|
116
405
|
// pack and oprionally transform/handle an array (sync)...
|
|
117
|
-
//
|
|
118
|
-
// NOTE: if 'types/Array' is imported this will support throwing STOP
|
|
119
|
-
// from the handler.
|
|
120
|
-
// Due to the async nature of promises though the way stops are
|
|
121
|
-
// handled may be unpredictable -- the handlers can be run out
|
|
122
|
-
// of order, as the nested promises resolve and thus throwing
|
|
123
|
-
// stop will stop the handlers not yet run and not the next
|
|
124
|
-
// handlers in sequence.
|
|
125
|
-
// XXX EXPEREMENTAL: STOP...
|
|
126
|
-
// XXX ITER can we unwind (sync/async) generators one by one???
|
|
127
|
-
/* XXX this repeats part of the functionality of .__handle(..)
|
|
128
406
|
__pack: function(list, handler=undefined, onerror=undefined){
|
|
129
|
-
var that = this
|
|
130
|
-
// handle iterator...
|
|
131
|
-
// XXX ITER do we unwind the iterator here or wait to unwind later???
|
|
132
|
-
if(typeof(list) == 'object'
|
|
133
|
-
&& Symbol.iterator in list){
|
|
134
|
-
if(!onerror){
|
|
135
|
-
list = [...list]
|
|
136
|
-
// handle errors in input generator...
|
|
137
|
-
// NOTE: this does not offer the most control because semantically
|
|
138
|
-
// we bust behave in the same manner as <generator>.iter(..)
|
|
139
|
-
} else {
|
|
140
|
-
var res = []
|
|
141
|
-
try{
|
|
142
|
-
for(var e of list){
|
|
143
|
-
res.push(e) }
|
|
144
|
-
}catch(err){
|
|
145
|
-
var r = onerror(err)
|
|
146
|
-
r !== undefined
|
|
147
|
-
&& res.push(r) }
|
|
148
|
-
list = res } }
|
|
149
407
|
// handle iterable promise...
|
|
150
408
|
if(list instanceof IterablePromise){
|
|
151
409
|
return this.__handle(list.__packed, handler, onerror) }
|
|
152
410
|
// handle promise / async-iterator...
|
|
153
|
-
// XXX ITER do we unwind the iterator here or wait to unwind later???
|
|
154
411
|
if(typeof(list) == 'object'
|
|
155
412
|
&& Symbol.asyncIterator in list){
|
|
156
413
|
return list
|
|
157
414
|
.iter(handler, onerror)
|
|
158
415
|
.then(function(list){
|
|
159
416
|
return that.__pack(list) }) }
|
|
160
|
-
if(list instanceof Promise){
|
|
161
|
-
return list
|
|
162
|
-
.then(function(list){
|
|
163
|
-
return that.__pack(list, handler, onerror) }) }
|
|
164
|
-
// do the work...
|
|
165
|
-
// NOTE: packing and handling are mixed here because it's faster
|
|
166
|
-
// to do them both on a single list traverse...
|
|
167
|
-
var handle = !!handler
|
|
168
|
-
handler = handler
|
|
169
|
-
?? function(elem){
|
|
170
|
-
return [elem] }
|
|
171
|
-
// XXX this repeats .__handle(..), need to unify...
|
|
172
|
-
var stop = false
|
|
173
|
-
var map = 'map'
|
|
174
|
-
var pack = function(){
|
|
175
|
-
return [list].flat()
|
|
176
|
-
[map](function(elem){
|
|
177
|
-
// XXX EXPEREMENTAL...
|
|
178
|
-
return elem instanceof IterablePromise ?
|
|
179
|
-
(elem.isSync() ?
|
|
180
|
-
handler(elem.sync())
|
|
181
|
-
// XXX need to handle this but keep it IterablePromise...
|
|
182
|
-
: elem.iterthen(handler))
|
|
183
|
-
: (elem instanceof SyncPromise
|
|
184
|
-
&& !(elem.sync() instanceof Promise)) ?
|
|
185
|
-
handler(elem.sync())
|
|
186
|
-
: elem && elem.then ?
|
|
187
|
-
(handleSTOP ?
|
|
188
|
-
// stoppable -- need to handle stop async...
|
|
189
|
-
elem
|
|
190
|
-
.then(function(res){
|
|
191
|
-
return !stop ?
|
|
192
|
-
handler(res)
|
|
193
|
-
: [] })
|
|
194
|
-
// NOTE: we are using .catch(..) here
|
|
195
|
-
// instead of directly passing the
|
|
196
|
-
// error handler to be able to catch
|
|
197
|
-
// the STOP from the handler...
|
|
198
|
-
.catch(handleSTOP)
|
|
199
|
-
// non-stoppable...
|
|
200
|
-
: elem.then(handler))
|
|
201
|
-
: elem instanceof Array ?
|
|
202
|
-
handler(elem)
|
|
203
|
-
// NOTE: we keep things that do not need protecting
|
|
204
|
-
// from .flat() as-is...
|
|
205
|
-
: !handle ?
|
|
206
|
-
elem
|
|
207
|
-
: handler(elem) }) }
|
|
208
|
-
// pack (stoppable)...
|
|
209
|
-
if(!!this.constructor.STOP){
|
|
210
|
-
map = 'smap'
|
|
211
|
-
var handleSTOP = function(err){
|
|
212
|
-
// handle stop...
|
|
213
|
-
stop = err
|
|
214
|
-
if(err === that.constructor.STOP
|
|
215
|
-
|| err instanceof that.constructor.STOP){
|
|
216
|
-
return 'value' in err ?
|
|
217
|
-
err.value
|
|
218
|
-
: [] }
|
|
219
|
-
throw err }
|
|
220
|
-
try{
|
|
221
|
-
return pack()
|
|
222
|
-
}catch(err){
|
|
223
|
-
return handleSTOP(err) } }
|
|
224
417
|
|
|
225
|
-
//
|
|
226
|
-
|
|
227
|
-
// transform/handle packed array (sync, but can return promises in the list)...
|
|
228
|
-
__handle: function(list, handler=undefined, onerror=undefined){
|
|
229
|
-
var that = this
|
|
230
|
-
if(typeof(list) == 'function'){
|
|
231
|
-
handler = list
|
|
232
|
-
list = this.__packed }
|
|
233
|
-
if(!handler){
|
|
234
|
-
return list }
|
|
235
|
-
// handle promise list...
|
|
236
|
-
if(list instanceof Promise){
|
|
237
|
-
return list.then(function(list){
|
|
238
|
-
return that.__handle(list, handler, onerror) }) }
|
|
239
|
-
// do the work...
|
|
240
|
-
// NOTE: since each section of the packed .__array is the same
|
|
241
|
-
// structure as the input we'll use .__pack(..) to handle
|
|
242
|
-
// them, this also keeps all the handling code in one place.
|
|
243
|
-
var map = !!this.constructor.STOP ?
|
|
244
|
-
'smap'
|
|
245
|
-
: 'map'
|
|
246
|
-
return list[map](function(elem){
|
|
247
|
-
elem = elem instanceof Array
|
|
248
|
-
|| elem instanceof Promise ?
|
|
249
|
-
that.__pack(elem, handler, onerror)
|
|
250
|
-
: [handler(elem)]
|
|
251
|
-
elem = elem instanceof Promise ?
|
|
252
|
-
elem.then(function([e]){
|
|
253
|
-
return e })
|
|
254
|
-
: elem
|
|
255
|
-
return elem })
|
|
256
|
-
.flat() },
|
|
257
|
-
/*/
|
|
258
|
-
__pack: function(list, handler=undefined, onerror=undefined){
|
|
259
|
-
var that = this
|
|
260
|
-
// handle iterator...
|
|
261
|
-
// XXX ITER do we unwind the iterator here or wait to unwind later???
|
|
262
|
-
if(typeof(list) == 'object'
|
|
263
|
-
&& Symbol.iterator in list){
|
|
264
|
-
if(!onerror){
|
|
265
|
-
list = [...list]
|
|
266
|
-
// handle errors in input generator...
|
|
267
|
-
// NOTE: this does not offer the most control because semantically
|
|
268
|
-
// we bust behave in the same manner as <generator>.iter(..)
|
|
269
|
-
} else {
|
|
270
|
-
var res = []
|
|
271
|
-
try{
|
|
272
|
-
for(var e of list){
|
|
273
|
-
res.push(e) }
|
|
274
|
-
}catch(err){
|
|
275
|
-
var r = onerror(err)
|
|
276
|
-
r !== undefined
|
|
277
|
-
&& res.push(r) }
|
|
278
|
-
list = res } }
|
|
279
|
-
// handle iterable promise...
|
|
280
|
-
if(list instanceof IterablePromise){
|
|
281
|
-
return this.__handle(list.__packed, handler, onerror) }
|
|
282
|
-
// handle promise / async-iterator...
|
|
283
|
-
// XXX ITER do we unwind the iterator here or wait to unwind later???
|
|
284
|
-
if(typeof(list) == 'object'
|
|
285
|
-
&& Symbol.asyncIterator in list){
|
|
286
|
-
return list
|
|
287
|
-
.iter(handler, onerror)
|
|
288
|
-
.then(function(list){
|
|
289
|
-
return that.__pack(list) }) }
|
|
290
|
-
if(list instanceof Promise){
|
|
291
|
-
return list
|
|
292
|
-
.then(function(list){
|
|
293
|
-
return that.__pack(list, handler, onerror) }) }
|
|
294
|
-
// pack...
|
|
295
|
-
list = [list].flat()
|
|
296
|
-
.map(function(elem){
|
|
297
|
-
return elem instanceof Array ?
|
|
298
|
-
[elem]
|
|
299
|
-
: elem instanceof Promise ?
|
|
300
|
-
elem.then(function(e){
|
|
301
|
-
return [e] })
|
|
302
|
-
: elem })
|
|
418
|
+
// do the packing...
|
|
419
|
+
var packed = module.packed.pack(list)
|
|
303
420
|
// handle if needed...
|
|
304
421
|
return handler ?
|
|
305
|
-
this.__handle(
|
|
306
|
-
:
|
|
422
|
+
this.__handle(packed, handler, onerror)
|
|
423
|
+
: packed },
|
|
307
424
|
// transform/handle packed array (sync, but can return promises in the list)...
|
|
308
|
-
|
|
309
|
-
__handle: function(list, handler=undefined, onerror=undefined){
|
|
425
|
+
__handle: function(packed, handler=undefined, onerror=undefined){
|
|
310
426
|
var that = this
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
427
|
+
// do .__handle(<func>)
|
|
428
|
+
if(typeof(packed) == 'function'){
|
|
429
|
+
handler = packed
|
|
430
|
+
packed = this.__packed }
|
|
314
431
|
if(!handler){
|
|
315
|
-
return
|
|
316
|
-
|
|
317
|
-
if(list instanceof Promise){
|
|
318
|
-
return list.then(function(list){
|
|
319
|
-
return that.__handle(list, handler, onerror) }) }
|
|
320
|
-
// do the work...
|
|
321
|
-
list = list instanceof Array ?
|
|
322
|
-
list
|
|
323
|
-
: [list]
|
|
324
|
-
var map = !!this.constructor.STOP ?
|
|
325
|
-
'smap'
|
|
326
|
-
: 'map'
|
|
327
|
-
var stop = false
|
|
328
|
-
// XXX do we handle generators here???
|
|
329
|
-
var each = function(elem){
|
|
330
|
-
return elem instanceof Array ?
|
|
331
|
-
elem
|
|
332
|
-
.map(handler)
|
|
333
|
-
.flat()
|
|
334
|
-
: handler(elem) }
|
|
335
|
-
return list
|
|
336
|
-
[map](
|
|
337
|
-
function(elem){
|
|
338
|
-
// NOTE: we are calling .flat() on the result so we
|
|
339
|
-
// need to keep a handled array as a single
|
|
340
|
-
// element by wrapping the return of handled(..)...
|
|
341
|
-
return elem instanceof IterablePromise ?
|
|
342
|
-
(elem.isSync() ?
|
|
343
|
-
each(elem.sync())
|
|
344
|
-
: elem.iterthen(each))
|
|
345
|
-
// sync sync promise...
|
|
346
|
-
: (elem instanceof SyncPromise
|
|
347
|
-
&& !(elem.sync() instanceof Promise)) ?
|
|
348
|
-
[each(elem.sync())]
|
|
349
|
-
// promise / promise-like...
|
|
350
|
-
: elem && elem.then ?
|
|
351
|
-
// NOTE: when this is explicitly stopped we
|
|
352
|
-
// do not call any more handlers after
|
|
353
|
-
// STOP is thrown/returned...
|
|
354
|
-
// NOTE: the promise protects this from .flat()
|
|
355
|
-
elem.then(function(elem){
|
|
356
|
-
return !stop ?
|
|
357
|
-
each(elem)
|
|
358
|
-
: [] })
|
|
359
|
-
: elem instanceof Array ?
|
|
360
|
-
[each(elem)]
|
|
361
|
-
: each(elem) },
|
|
362
|
-
// handle STOP...
|
|
363
|
-
function(){
|
|
364
|
-
stop = true })
|
|
365
|
-
.flat() },
|
|
366
|
-
//*/
|
|
367
|
-
// XXX this should return IterablePromise if .__packed is partially sync (???)
|
|
432
|
+
return packed }
|
|
433
|
+
return module.packed.handle(packed, ...[...arguments].slice(1)) },
|
|
368
434
|
// unpack array (sync/async)...
|
|
369
|
-
__unpack: function(
|
|
370
|
-
|
|
435
|
+
__unpack: function(packed){
|
|
436
|
+
// do .__unpack()
|
|
437
|
+
packed = packed
|
|
371
438
|
?? this.__packed
|
|
372
439
|
// handle promise list...
|
|
373
|
-
if(
|
|
374
|
-
return
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
var res = []
|
|
379
|
-
for(var e of list){
|
|
380
|
-
if(e instanceof IterablePromise){
|
|
381
|
-
e = e.__unpack() }
|
|
382
|
-
if(e instanceof SyncPromise){
|
|
383
|
-
e = e.sync() }
|
|
384
|
-
// give up on a sync solution...
|
|
385
|
-
if(e instanceof Promise){
|
|
386
|
-
// XXX can we return an IterablePromise???
|
|
387
|
-
// XXX is there a more elegant way to do this???
|
|
388
|
-
return Promise.all(list)
|
|
389
|
-
.then(function(list){
|
|
390
|
-
return list.flat() })
|
|
391
|
-
.iter() }
|
|
392
|
-
res.push(e) }
|
|
393
|
-
return res.flat() },
|
|
394
|
-
|
|
440
|
+
if(packed instanceof IterablePromise){
|
|
441
|
+
return packed.__unpack() }
|
|
442
|
+
return module.packed.unpack(packed) },
|
|
443
|
+
|
|
444
|
+
|
|
395
445
|
[Symbol.asyncIterator]: async function*(){
|
|
396
446
|
var list = this.__packed
|
|
397
447
|
if(list instanceof Promise){
|
|
@@ -415,22 +465,19 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
415
465
|
map: function(func){
|
|
416
466
|
return this.constructor(this,
|
|
417
467
|
function(e){
|
|
418
|
-
|
|
419
|
-
return res instanceof Promise ?
|
|
420
|
-
res.then(function(e){
|
|
421
|
-
return [e] })
|
|
422
|
-
: [res] }) },
|
|
468
|
+
return [func(e)] }) },
|
|
423
469
|
filter: function(func){
|
|
424
470
|
return this.constructor(this,
|
|
425
471
|
function(e){
|
|
426
472
|
var res = func(e)
|
|
427
|
-
var _filter = function(elem){
|
|
428
|
-
return res ?
|
|
429
|
-
[elem]
|
|
430
|
-
: [] }
|
|
431
473
|
return res instanceof Promise ?
|
|
432
|
-
res.then(
|
|
433
|
-
|
|
474
|
+
res.then(function(res){
|
|
475
|
+
return res ?
|
|
476
|
+
[e]
|
|
477
|
+
: [] })
|
|
478
|
+
: res ?
|
|
479
|
+
[e]
|
|
480
|
+
: [] }) },
|
|
434
481
|
// NOTE: this does not return an iterable promise as we can't know
|
|
435
482
|
// what the user reduces to...
|
|
436
483
|
// NOTE: the items can be handled out of order because the nested
|
|
@@ -756,6 +803,7 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
756
803
|
// NOTE: if 'types/Array' is imported this will support throwing STOP,
|
|
757
804
|
// for more info see notes for .__pack(..)
|
|
758
805
|
// XXX EXPEREMENTAL: STOP...
|
|
806
|
+
// XXX use selfResolve(..)
|
|
759
807
|
__new__: function(_, list, handler=undefined, onerror=undefined){
|
|
760
808
|
// instance...
|
|
761
809
|
var promise
|
|
@@ -803,12 +851,16 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
803
851
|
list instanceof Promise ?
|
|
804
852
|
list.then(function(list){
|
|
805
853
|
obj.__packed = list })
|
|
854
|
+
/*/ XXX use selfResolve(..)
|
|
855
|
+
: selfResolve(list) }
|
|
856
|
+
/*/
|
|
806
857
|
: list.forEach(function(elem, i){
|
|
807
858
|
elem instanceof Promise
|
|
808
859
|
&& elem.then(function(elem){
|
|
809
860
|
lst = obj.__packed.slice()
|
|
810
861
|
lst[i] = elem
|
|
811
862
|
obj.__packed = lst }) }) }
|
|
863
|
+
//*/
|
|
812
864
|
return obj },
|
|
813
865
|
})
|
|
814
866
|
|
|
@@ -816,6 +868,7 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
816
868
|
|
|
817
869
|
//---------------------------------------------------------------------
|
|
818
870
|
// XXX EXPEREMENTAL/HACK...
|
|
871
|
+
// Sequential iterable promise...
|
|
819
872
|
|
|
820
873
|
// This like IterablePromise but guarantees handler execution in order
|
|
821
874
|
// element occurrence.
|
|
@@ -827,7 +880,7 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
827
880
|
// Promise.iter([ .. ]).iter(func)
|
|
828
881
|
// - func per element
|
|
829
882
|
// - func is called when an element is resolved/ready
|
|
830
|
-
// in
|
|
883
|
+
// in order of resolution/readiness
|
|
831
884
|
// Promise.seqiter([ .. ]).iter(func)
|
|
832
885
|
// - func per element
|
|
833
886
|
// - func is called when an element is resolved/ready
|
|
@@ -836,6 +889,13 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
836
889
|
// NOTE: that here a promise will block handling of later promises even
|
|
837
890
|
// if they are resolved before it.
|
|
838
891
|
//
|
|
892
|
+
// XXX is this correct???
|
|
893
|
+
// > g = function*(){ yield* [1,2,3] }
|
|
894
|
+
// // XXX should this expand the generator???
|
|
895
|
+
// > await Promise.seqiter([0, g()])
|
|
896
|
+
// -> [ 0, Object [Generator] {} ]
|
|
897
|
+
// > await Promise.seqiter([0, g()]).flat()
|
|
898
|
+
// -> [ 0, 1, 2, 3 ]
|
|
839
899
|
// XXX check if this behaves correctly (call order) on concatenation and
|
|
840
900
|
// other methods...
|
|
841
901
|
// XXX not sure if this is a viable strategy....
|
|
@@ -848,13 +908,14 @@ object.Constructor('IterableSequentialPromise', IterablePromise, {
|
|
|
848
908
|
var repack = function(list){
|
|
849
909
|
var res = []
|
|
850
910
|
for(var [i, e] of list.entries()){
|
|
851
|
-
// XXX check for .then(..) instead???
|
|
852
|
-
//if(e instanceof Promise
|
|
853
911
|
if(e.then
|
|
854
912
|
// skip last promise -- nothing to wrap...
|
|
855
913
|
&& i < list.length-1){
|
|
856
914
|
res.push(e
|
|
857
915
|
.then(function(e){
|
|
916
|
+
// NOTE: this does not call any handlers, thus
|
|
917
|
+
// there should be no risk of out of order
|
|
918
|
+
// handler execution....
|
|
858
919
|
return seqiter(
|
|
859
920
|
[e, ...list.slice(i+1)])
|
|
860
921
|
.flat() }))
|
|
@@ -867,14 +928,12 @@ object.Constructor('IterableSequentialPromise', IterablePromise, {
|
|
|
867
928
|
list = list instanceof SyncPromise ?
|
|
868
929
|
list.sync()
|
|
869
930
|
: list
|
|
931
|
+
// repack...
|
|
870
932
|
list = list instanceof Array ?
|
|
871
933
|
repack(list)
|
|
872
|
-
// XXX check for .then(..) instead???
|
|
873
|
-
//: list instanceof Promise ?
|
|
874
934
|
: list.then ?
|
|
875
935
|
list.then(repack)
|
|
876
936
|
: list
|
|
877
|
-
|
|
878
937
|
return handler ?
|
|
879
938
|
this.__handle(list, handler, onerror)
|
|
880
939
|
: list },
|
package/package.json
CHANGED
package/runner.js
CHANGED
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
* - ...
|
|
13
13
|
* would be nice to make the task just a slightly extended or better
|
|
14
14
|
* defined function/generator, ideally to make them interchangable...
|
|
15
|
+
* XXX BUG: there seems to be an odd bug somplace here where each item
|
|
16
|
+
* gets processed once per "thread"... (ImageGrid.Viewer export)
|
|
15
17
|
*
|
|
16
18
|
**********************************************/ /* c8 ignore next 2 */
|
|
17
19
|
((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define)
|
|
@@ -360,6 +362,7 @@ object.Constructor('Queue', Array, {
|
|
|
360
362
|
// report...
|
|
361
363
|
that.trigger('taskCompleted', task, res) }
|
|
362
364
|
var fail = {doc: 'fail runningDone(..)'}
|
|
365
|
+
// XXX should this also remove .__running when empty???
|
|
363
366
|
var runningDone = function(mode){
|
|
364
367
|
running.splice(0, running.length,
|
|
365
368
|
// NOTE: there can be multiple occurrences of res...
|
|
@@ -409,7 +412,7 @@ object.Constructor('Queue', Array, {
|
|
|
409
412
|
// collect results...
|
|
410
413
|
this.collect_results
|
|
411
414
|
&& res !== module.SKIP
|
|
412
|
-
&& (this.__results = this.__results
|
|
415
|
+
&& (this.__results = this.__results ?? []).push(res)
|
|
413
416
|
|
|
414
417
|
// handle task results...
|
|
415
418
|
//
|
|
@@ -516,6 +519,9 @@ object.Constructor('Queue', Array, {
|
|
|
516
519
|
//
|
|
517
520
|
// NOTE: this helps get around the argument number limitation in JS...
|
|
518
521
|
add: function(tasks){
|
|
522
|
+
tasks = tasks instanceof Array ?
|
|
523
|
+
tasks
|
|
524
|
+
: [tasks]
|
|
519
525
|
// handle too large a number of args...
|
|
520
526
|
var MAX_ARGS = 10000
|
|
521
527
|
if(tasks.length > MAX_ARGS){
|
|
@@ -568,37 +574,51 @@ module.FinalizableQueue =
|
|
|
568
574
|
object.Constructor('FinalizableQueue', Queue, {
|
|
569
575
|
auto_stop: true,
|
|
570
576
|
|
|
577
|
+
// not for direct use...
|
|
578
|
+
__freeze: function(){
|
|
579
|
+
Object.freeze(this)
|
|
580
|
+
// XXX do we remove/freeze .__running???
|
|
581
|
+
this.__results
|
|
582
|
+
&& Object.freeze(this.__results)
|
|
583
|
+
return this },
|
|
584
|
+
|
|
571
585
|
__onempty__: function(){
|
|
572
586
|
return this.trigger('done') },
|
|
573
587
|
|
|
574
588
|
done: events.Event('done', function(handle){
|
|
575
589
|
// abort only once...
|
|
576
|
-
if(this.state == 'aborted'
|
|
590
|
+
if(this.state == 'aborted'
|
|
591
|
+
|| this.state == 'done'){
|
|
577
592
|
return handle(false) }
|
|
578
593
|
this.__state = 'done'
|
|
579
|
-
|
|
594
|
+
this.__freeze() }),
|
|
580
595
|
abort: events.Event('abort', function(handle){
|
|
581
596
|
// abort only once...
|
|
582
|
-
if(this.state == 'aborted'
|
|
597
|
+
if(this.state == 'aborted'
|
|
598
|
+
|| this.state == 'done'){
|
|
583
599
|
return handle(false) }
|
|
584
600
|
this.__state = 'aborted'
|
|
585
|
-
|
|
601
|
+
this.__freeze() }),
|
|
586
602
|
|
|
587
603
|
// NOTE: each handler will get called once when the next time the
|
|
588
604
|
// queue is emptied...
|
|
589
605
|
promise: function(){
|
|
606
|
+
return this.__promise },
|
|
607
|
+
then: function(onresolve, onreject){
|
|
608
|
+
return this.promise().then(...arguments) },
|
|
609
|
+
catch: function(onreject){
|
|
610
|
+
return this.promise().catch(...arguments) },
|
|
611
|
+
|
|
612
|
+
__init__: function(options){
|
|
590
613
|
var that = this
|
|
591
|
-
|
|
614
|
+
this.__promise = new Promise(function(resolve, reject){
|
|
592
615
|
that
|
|
593
616
|
.one('done', function(){
|
|
594
617
|
resolve(...(that.collect_results ?
|
|
595
|
-
[that.__results
|
|
618
|
+
[that.__results ?? []]
|
|
596
619
|
: [])) })
|
|
597
|
-
.one('abort', reject) })
|
|
598
|
-
|
|
599
|
-
return this.promise().then(...arguments) },
|
|
600
|
-
catch: function(onreject){
|
|
601
|
-
return this.promise().catch(...arguments) },
|
|
620
|
+
.one('abort', reject) })
|
|
621
|
+
return object.parentCall(FinalizableQueue.prototype.__init__, this, ...arguments) },
|
|
602
622
|
})
|
|
603
623
|
|
|
604
624
|
|
package/test.js
CHANGED
|
@@ -112,9 +112,9 @@ var cases = test.Cases({
|
|
|
112
112
|
},
|
|
113
113
|
|
|
114
114
|
IterablePromise: test.TestSet(function(){
|
|
115
|
-
var create = function(assert, value){
|
|
115
|
+
var create = function(assert, value, expected){
|
|
116
116
|
return {
|
|
117
|
-
input: value,
|
|
117
|
+
input: expected ?? value,
|
|
118
118
|
output: assert(Promise.iter(value), 'Promise.iter(', value, ')'),
|
|
119
119
|
} }
|
|
120
120
|
|
|
@@ -136,29 +136,53 @@ var cases = test.Cases({
|
|
|
136
136
|
array_mixed: function(assert){
|
|
137
137
|
return create(assert, [1, Promise.resolve(2), 3]) },
|
|
138
138
|
nested_array_mixed: function(assert){
|
|
139
|
-
return create(assert,
|
|
140
|
-
1,
|
|
141
|
-
|
|
142
|
-
[3],
|
|
143
|
-
Promise.resolve([4]),
|
|
144
|
-
]) },
|
|
139
|
+
return create(assert,
|
|
140
|
+
[1, Promise.resolve(2), [3], Promise.resolve([4])],
|
|
141
|
+
[1, 2, [3], [4]]) },
|
|
145
142
|
promise_array_mixed: function(assert){
|
|
146
|
-
return create(assert,
|
|
143
|
+
return create(assert,
|
|
144
|
+
Promise.resolve([1, Promise.resolve(2), 3]),
|
|
145
|
+
[1, 2, 3]) },
|
|
147
146
|
promise_nested_array_mixed: function(assert){
|
|
148
|
-
return create(assert,
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
147
|
+
return create(assert,
|
|
148
|
+
Promise.resolve([
|
|
149
|
+
1,
|
|
150
|
+
Promise.resolve(2),
|
|
151
|
+
[3],
|
|
152
|
+
Promise.resolve([4]),
|
|
153
|
+
]),
|
|
154
|
+
[1, 2, [3], [4]]) },
|
|
154
155
|
})
|
|
155
156
|
this.Modifier({
|
|
156
157
|
nest: function(assert, setup){
|
|
157
158
|
setup.output = Promise.iter(setup.output)
|
|
158
159
|
return setup },
|
|
159
|
-
|
|
160
|
+
iter_noargs: function(assert, setup){
|
|
160
161
|
setup.output = setup.output.iter()
|
|
161
162
|
return setup },
|
|
163
|
+
iter_asis: function(assert, setup){
|
|
164
|
+
setup.output = setup.output
|
|
165
|
+
.iter(function(e){
|
|
166
|
+
return [e] })
|
|
167
|
+
return setup },
|
|
168
|
+
iter_clear: function(assert, setup){
|
|
169
|
+
return {
|
|
170
|
+
input: [],
|
|
171
|
+
output: setup.output
|
|
172
|
+
.iter(function(e){
|
|
173
|
+
return [] }),
|
|
174
|
+
} },
|
|
175
|
+
/* XXX does not account for promises as input...
|
|
176
|
+
iter_flat: async function(assert, setup){
|
|
177
|
+
return {
|
|
178
|
+
input: setup.input instanceof Array ?
|
|
179
|
+
(await Promise.all(setup.input)).flat()
|
|
180
|
+
: [await setup.input],
|
|
181
|
+
output: setup.output
|
|
182
|
+
.iter(function(e){
|
|
183
|
+
return e }),
|
|
184
|
+
} },
|
|
185
|
+
//*/
|
|
162
186
|
|
|
163
187
|
map_asis: function(assert, setup){
|
|
164
188
|
setup.output = setup.output
|
|
@@ -182,6 +206,19 @@ var cases = test.Cases({
|
|
|
182
206
|
output: setup.output
|
|
183
207
|
.filter(function(e){ return false }),
|
|
184
208
|
} },
|
|
209
|
+
filter_promise_all: function(assert, setup){
|
|
210
|
+
setup.output = setup.output
|
|
211
|
+
.filter(function(e){
|
|
212
|
+
return Promise.resolve(true) })
|
|
213
|
+
return setup },
|
|
214
|
+
filter_promise_none: function(assert, setup){
|
|
215
|
+
return {
|
|
216
|
+
input: [],
|
|
217
|
+
output: setup.output
|
|
218
|
+
.filter(function(e){
|
|
219
|
+
return Promise.resolve(false) }),
|
|
220
|
+
} },
|
|
221
|
+
//*/
|
|
185
222
|
|
|
186
223
|
/* XXX need tuning...
|
|
187
224
|
concat_basic: function(assert, {input, output}){
|
|
@@ -300,6 +337,118 @@ var cases = test.Cases({
|
|
|
300
337
|
[1,2,3],
|
|
301
338
|
'flat unpack', meth)
|
|
302
339
|
}
|
|
340
|
+
|
|
341
|
+
var order = []
|
|
342
|
+
await Promise.seqiter([
|
|
343
|
+
1,
|
|
344
|
+
Promise.resolve(2),
|
|
345
|
+
Promise.all([3,4]),
|
|
346
|
+
Promise.seqiter([5]),
|
|
347
|
+
6,
|
|
348
|
+
])
|
|
349
|
+
.flat()
|
|
350
|
+
.map(function(e){
|
|
351
|
+
order.push(e)
|
|
352
|
+
return e })
|
|
353
|
+
assert.array(
|
|
354
|
+
order,
|
|
355
|
+
[1,2,3,4,5,6],
|
|
356
|
+
'Promise.seqiter(..) handle order')
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
var test_async_handler = async function(input, output, handler, msg){
|
|
360
|
+
// sanity check...
|
|
361
|
+
assert.array(
|
|
362
|
+
await Promise.iter(input, handler),
|
|
363
|
+
output,
|
|
364
|
+
msg+' (sanity check -- fix first)')
|
|
365
|
+
assert.array(
|
|
366
|
+
await Promise.iter(input,
|
|
367
|
+
function(e){
|
|
368
|
+
return Promise.resolve(handler(e)) }),
|
|
369
|
+
await Promise.iter(input, handler),
|
|
370
|
+
msg) }
|
|
371
|
+
|
|
372
|
+
await test_async_handler(
|
|
373
|
+
[
|
|
374
|
+
1,
|
|
375
|
+
[2],
|
|
376
|
+
Promise.resolve(3),
|
|
377
|
+
Promise.resolve([4]),
|
|
378
|
+
],
|
|
379
|
+
[],
|
|
380
|
+
function(e){
|
|
381
|
+
return [] },
|
|
382
|
+
'handler returns promise (empty)')
|
|
383
|
+
await test_async_handler(
|
|
384
|
+
[
|
|
385
|
+
1,
|
|
386
|
+
[2],
|
|
387
|
+
Promise.resolve(3),
|
|
388
|
+
Promise.resolve([4]),
|
|
389
|
+
],
|
|
390
|
+
[ 'moo', 'moo', 'moo', 'moo' ],
|
|
391
|
+
function(e){
|
|
392
|
+
return ['moo'] },
|
|
393
|
+
'handler returns promise (array)')
|
|
394
|
+
await test_async_handler(
|
|
395
|
+
[
|
|
396
|
+
1,
|
|
397
|
+
[2],
|
|
398
|
+
Promise.resolve(3),
|
|
399
|
+
Promise.resolve([4]),
|
|
400
|
+
],
|
|
401
|
+
[ ['moo'], ['moo'], ['moo'], ['moo'] ],
|
|
402
|
+
function(e){
|
|
403
|
+
return [['moo']] },
|
|
404
|
+
'handler returns promise (array-array)')
|
|
405
|
+
|
|
406
|
+
// test STOP...
|
|
407
|
+
assert.array(
|
|
408
|
+
await Promise.iter([1,2,3,4], function(e){
|
|
409
|
+
if(e == 3){
|
|
410
|
+
throw Array.STOP }
|
|
411
|
+
return e }),
|
|
412
|
+
[1,2],
|
|
413
|
+
'.iter(..): STOP: basic')
|
|
414
|
+
assert.array(
|
|
415
|
+
await Promise.iter([1,2,Promise.resolve(3),4], function(e){
|
|
416
|
+
if(e == 3){
|
|
417
|
+
throw Array.STOP }
|
|
418
|
+
return e }),
|
|
419
|
+
// NOTE: 4 here is present as it was handled before the promise resolved...
|
|
420
|
+
[1,2,4],
|
|
421
|
+
'.iter(..): STOP: delayed')
|
|
422
|
+
assert.array(
|
|
423
|
+
await Promise.iter([1,2,Promise.resolve(3),4], function(e){
|
|
424
|
+
if(e == 3){
|
|
425
|
+
throw Array.STOP('stop') }
|
|
426
|
+
return e }),
|
|
427
|
+
// NOTE: 4 here is present as it was handled before the promise resolved...
|
|
428
|
+
[1,2,'stop',4],
|
|
429
|
+
'.iter(..): STOP(..): delayed')
|
|
430
|
+
assert.array(
|
|
431
|
+
await Promise.seqiter([1,2,3,4], function(e){
|
|
432
|
+
if(e == 3){
|
|
433
|
+
throw Array.STOP }
|
|
434
|
+
return e }),
|
|
435
|
+
[1,2],
|
|
436
|
+
'.seqiter(..): STOP: basic')
|
|
437
|
+
assert.array(
|
|
438
|
+
await Promise.seqiter([1,2,Promise.resolve(3),4], function(e){
|
|
439
|
+
if(e == 3){
|
|
440
|
+
throw Array.STOP }
|
|
441
|
+
return e }),
|
|
442
|
+
[1,2],
|
|
443
|
+
'.seqiter(..): STOP: delayed')
|
|
444
|
+
assert.array(
|
|
445
|
+
await Promise.seqiter([1,2,Promise.resolve(3),4], function(e){
|
|
446
|
+
if(e == 3){
|
|
447
|
+
throw Array.STOP('stop') }
|
|
448
|
+
return e }),
|
|
449
|
+
// NOTE: 4 here is present as it was handled before the promise resolved...
|
|
450
|
+
[1,2,'stop'],
|
|
451
|
+
'.seqiter(..): STOP(..): delayed')
|
|
303
452
|
},
|
|
304
453
|
|
|
305
454
|
// Date.js
|
|
@@ -557,8 +706,8 @@ Events.cases({
|
|
|
557
706
|
|
|
558
707
|
|
|
559
708
|
// test event list...
|
|
560
|
-
assert.array(obj.events, ['
|
|
561
|
-
assert.array(obj.eventful, ['
|
|
709
|
+
assert.array(obj.events, ['eventBlank', 'event'], '.events')
|
|
710
|
+
assert.array(obj.eventful, ['bareEventBlank', 'bareEvent'], '.eventful')
|
|
562
711
|
|
|
563
712
|
// bind...
|
|
564
713
|
var bind = function(evt){
|