ig-types 6.11.2 → 6.12.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 +43 -8
- package/README.md +75 -28
- package/package.json +1 -1
- package/Promise.js.bak +0 -548
package/Promise.js
CHANGED
|
@@ -121,6 +121,14 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
121
121
|
return [] })
|
|
122
122
|
.then(function(){
|
|
123
123
|
return res }) },
|
|
124
|
+
/* // XXX since order of execution is not fixed there is no point in
|
|
125
|
+
// adding this.
|
|
126
|
+
reduceRight: function(func, res){
|
|
127
|
+
return this
|
|
128
|
+
.reverse()
|
|
129
|
+
.reduce(...arguments)
|
|
130
|
+
.reverse() },
|
|
131
|
+
//*/
|
|
124
132
|
flat: function(depth=1){
|
|
125
133
|
return this.constructor(this,
|
|
126
134
|
function(e){
|
|
@@ -152,18 +160,45 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
152
160
|
.reverse(),
|
|
153
161
|
'raw') },
|
|
154
162
|
|
|
163
|
+
// NOTE: these can create an unresolved promise from a resolved
|
|
164
|
+
// promise...
|
|
165
|
+
// XXX EXPEREMENTAL...
|
|
166
|
+
// ....can we remove a level of indirection here???
|
|
167
|
+
// would be better to use the raw mode...
|
|
168
|
+
concat: function(other){
|
|
169
|
+
var lst = this.__list
|
|
170
|
+
return lst instanceof Promise ?
|
|
171
|
+
this.constructor([this, other])
|
|
172
|
+
.flat()
|
|
173
|
+
: other instanceof IterablePromise ?
|
|
174
|
+
this.constructor(
|
|
175
|
+
lst.concat(other.__list),
|
|
176
|
+
'raw')
|
|
177
|
+
: other instanceof Promise ?
|
|
178
|
+
this.constructor(
|
|
179
|
+
lst.concat(other
|
|
180
|
+
.then(function(res){
|
|
181
|
+
return res instanceof Array ?
|
|
182
|
+
res
|
|
183
|
+
: [res] })),
|
|
184
|
+
'raw')
|
|
185
|
+
: this.constructor(
|
|
186
|
+
// XXX this is cheating -- need a more direct way to form the array...
|
|
187
|
+
lst.concat(this.constructor(other).__list),
|
|
188
|
+
'raw') },
|
|
189
|
+
push: function(elem){
|
|
190
|
+
return this.concat([elem]) },
|
|
191
|
+
unshift: function(elem){
|
|
192
|
+
return this.constructor([elem])
|
|
193
|
+
.concat(this) },
|
|
194
|
+
|
|
155
195
|
// XXX do we need these?
|
|
156
196
|
// .pop()
|
|
157
197
|
// .shift()
|
|
158
198
|
// .first() / .last()
|
|
159
|
-
//
|
|
160
|
-
//
|
|
161
|
-
|
|
162
|
-
// .concat(..)
|
|
163
|
-
// .push(..)
|
|
164
|
-
// .unshift(..)
|
|
165
|
-
// .first(..) / .last(..)
|
|
166
|
-
|
|
199
|
+
// ...would be nice if these could stop everything that's not
|
|
200
|
+
// needed to execute...
|
|
201
|
+
|
|
167
202
|
|
|
168
203
|
// Overload .then(..), .catch(..) and .finally(..) to return a plain
|
|
169
204
|
// Promise instnace...
|
package/README.md
CHANGED
|
@@ -75,6 +75,8 @@ Library of JavaScript type extensions, types and utilities.
|
|
|
75
75
|
- [`<promise-iter>.map(..)` / `<promise-iter>.filter(..)` / `<promise-iter>.reduce(..)`](#promise-itermap--promise-iterfilter--promise-iterreduce)
|
|
76
76
|
- [`<promise-iter>.flat(..)`](#promise-iterflat)
|
|
77
77
|
- [`<promise-iter>.reverse()`](#promise-iterreverse)
|
|
78
|
+
- [`<promise-iter>.concat(..)`](#promise-iterconcat)
|
|
79
|
+
- [`<promise-iter>.push(..)` / `<promise-iter>.unshift(..)`](#promise-iterpush--promise-iterunshift)
|
|
78
80
|
- [`<promise-iter>.then(..)` / `<promise-iter>.catch(..)` / `<promise-iter>.finally(..)`](#promise-iterthen--promise-itercatch--promise-iterfinally)
|
|
79
81
|
- [Advanced handler](#advanced-handler)
|
|
80
82
|
- [Promise proxies](#promise-proxies)
|
|
@@ -1387,7 +1389,7 @@ controlled(t.then())
|
|
|
1387
1389
|
// ...
|
|
1388
1390
|
```
|
|
1389
1391
|
|
|
1390
|
-
Note that functionally
|
|
1392
|
+
Note that this functionally can be considered a special-case of an
|
|
1391
1393
|
[interactive promise](#interactive-promises), but in reality they are two
|
|
1392
1394
|
different implementations, the main differences are:
|
|
1393
1395
|
- _Cooperative promise_ constructor does not need a resolver function,
|
|
@@ -1483,8 +1485,6 @@ var p = Promise.iter([ .. ])
|
|
|
1483
1485
|
// ...
|
|
1484
1486
|
})
|
|
1485
1487
|
// items reach here as soon as they are returned by the filter stage handler...
|
|
1486
|
-
// NOTE: the filter handler may return promises, those will not be processed
|
|
1487
|
-
// until they are resolved...
|
|
1488
1488
|
.map(function(e){
|
|
1489
1489
|
// ...
|
|
1490
1490
|
})
|
|
@@ -1502,6 +1502,12 @@ This approach has a number of advantages:
|
|
|
1502
1502
|
And some disadvantages:
|
|
1503
1503
|
- item indexes are unknowable until all the promises resolve.
|
|
1504
1504
|
|
|
1505
|
+
Calling each of the `<promise-iter>` methods will return a new and unresolved
|
|
1506
|
+
promise, even if the original is resolved.
|
|
1507
|
+
|
|
1508
|
+
If all values are resolved the `<promise-iter>` will resolve on the next
|
|
1509
|
+
execution frame.
|
|
1510
|
+
|
|
1505
1511
|
<!--
|
|
1506
1512
|
XXX should we support generators as input?
|
|
1507
1513
|
...not sure about the control flow direction here, on one hand the generator
|
|
@@ -1580,19 +1586,21 @@ and [`.reduce(..)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe
|
|
|
1580
1586
|
|
|
1581
1587
|
Note that these are different to `Array`'s equivalents in some details:
|
|
1582
1588
|
- `<handler>` is _not_ called in the order of element occurrence but rather
|
|
1583
|
-
|
|
1589
|
+
in the order of elements are resolved/ready.
|
|
1584
1590
|
- `<handler>` does not get either the element _index_ or the _container_.
|
|
1585
|
-
this is because
|
|
1586
|
-
index is
|
|
1591
|
+
this is because in _out-of-order_ and _depth-first_ execution the
|
|
1592
|
+
index is _unknowable_ and the container is a promise/black-box.
|
|
1587
1593
|
|
|
1588
|
-
This is especially critical for `.reduce(..)` as iteration in an order
|
|
1589
|
-
from the order of elements _can_ affect actual result if this is
|
|
1594
|
+
This is especially critical for `.reduce(..)` as the iteration in an order
|
|
1595
|
+
different from the order of elements _can_ affect actual result if this is
|
|
1596
|
+
not expected.
|
|
1590
1597
|
|
|
1591
1598
|
`.reduce(..)` is also a bit different here in that it will return a basic
|
|
1592
|
-
`<promise>` object as we can't know what
|
|
1599
|
+
`<promise>` rather than an iterable promise object as we can't know what
|
|
1600
|
+
will it will reduce to.
|
|
1593
1601
|
|
|
1594
|
-
Note that since `.reduce(..)` order can not be
|
|
1595
|
-
in implementing `.reduceRigth(..)`.
|
|
1602
|
+
Note that since `.reduce(..)` handler's execution order can not be known,
|
|
1603
|
+
there is no point in implementing `.reduceRigth(..)`.
|
|
1596
1604
|
|
|
1597
1605
|
|
|
1598
1606
|
#### `<promise-iter>.flat(..)`
|
|
@@ -1613,7 +1621,35 @@ This is similar to [`<array>.flat(..)`](https://developer.mozilla.org/en-US/docs
|
|
|
1613
1621
|
-> <promise-iter>
|
|
1614
1622
|
```
|
|
1615
1623
|
|
|
1616
|
-
This is
|
|
1624
|
+
This is deferent from `<array>.reverse()` in that it will _not_ reverse in-place,
|
|
1625
|
+
but rather a _reversed copy_ will be created.
|
|
1626
|
+
|
|
1627
|
+
This is similar to [`<array>.reverse()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse) see it for more info.
|
|
1628
|
+
|
|
1629
|
+
|
|
1630
|
+
#### `<promise-iter>.concat(..)`
|
|
1631
|
+
|
|
1632
|
+
```bnf
|
|
1633
|
+
<promise-iter>.concat(<other>)
|
|
1634
|
+
-> <promise-iter>
|
|
1635
|
+
```
|
|
1636
|
+
|
|
1637
|
+
This is similar to [`<array>.concat(..)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat) see it for more info.
|
|
1638
|
+
|
|
1639
|
+
|
|
1640
|
+
#### `<promise-iter>.push(..)` / `<promise-iter>.unshift(..)`
|
|
1641
|
+
|
|
1642
|
+
```bnf
|
|
1643
|
+
<promise-iter>.push(<elem>)
|
|
1644
|
+
-> <promise-iter>
|
|
1645
|
+
|
|
1646
|
+
<promise-iter>.unshift(<elem>)
|
|
1647
|
+
-> <promise-iter>
|
|
1648
|
+
```
|
|
1649
|
+
|
|
1650
|
+
These are similar to [`<array>.push(..)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push)
|
|
1651
|
+
and [`<array>.unshift(..)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/unshift)
|
|
1652
|
+
see them for more info.
|
|
1617
1653
|
|
|
1618
1654
|
|
|
1619
1655
|
#### `<promise-iter>.then(..)` / `<promise-iter>.catch(..)` / `<promise-iter>.finally(..)`
|
|
@@ -1633,40 +1669,51 @@ can be useful to hide the extended promise API from further code.
|
|
|
1633
1669
|
#### Advanced handler
|
|
1634
1670
|
|
|
1635
1671
|
```bnf
|
|
1636
|
-
Promise.iter(<block
|
|
1672
|
+
Promise.iter(<block>, <handler>)
|
|
1637
1673
|
-> <iterable-promise>
|
|
1674
|
+
```
|
|
1638
1675
|
|
|
1639
|
-
|
|
1640
|
-
|
|
1676
|
+
The `<handler>` will get passed each resolved `<value>` of the input `<block>`
|
|
1677
|
+
as soon as it's available/resolved.
|
|
1678
|
+
|
|
1679
|
+
The `<handler>` return value is unwrapped into the resulting array, allowing
|
|
1680
|
+
each call to both remove elements (i.e. returning `[]`) from the resulting
|
|
1681
|
+
`<block>` as well as insert multiple items (by returning an array of items).
|
|
1682
|
+
|
|
1683
|
+
<!-- XXX returning promises from handler needs to be documented/tested... -->
|
|
1684
|
+
|
|
1685
|
+
```bnf
|
|
1686
|
+
<handler>(<value>)
|
|
1687
|
+
-> []
|
|
1688
|
+
-> [ <elem>, .. ]
|
|
1689
|
+
-> <non-array>
|
|
1641
1690
|
```
|
|
1642
1691
|
|
|
1643
1692
|
```bnf
|
|
1644
|
-
<block
|
|
1693
|
+
<block> ::=
|
|
1645
1694
|
[]
|
|
1646
|
-
| [ <
|
|
1695
|
+
| [ <elem>, .. ]
|
|
1647
1696
|
|
|
1648
|
-
<
|
|
1649
|
-
|
|
1650
|
-
|
|
|
1651
|
-
| <promise>
|
|
1652
|
-
| <non-array>
|
|
1697
|
+
<elem> ::=
|
|
1698
|
+
<value>
|
|
1699
|
+
| <promise>(<value>)
|
|
1653
1700
|
```
|
|
1654
1701
|
|
|
1655
1702
|
Example:
|
|
1656
1703
|
```javascript
|
|
1657
1704
|
var p = Promise.iter(
|
|
1658
|
-
|
|
1659
|
-
// an array -- like the last element here...
|
|
1660
|
-
[[1, 2], 3, Promise.resolve(4), [[5, 6]]],
|
|
1705
|
+
[1, 2, 3, Promise.resolve(4), [5, 6]],
|
|
1661
1706
|
function(elem){
|
|
1707
|
+
// duplicate even numbers...
|
|
1662
1708
|
return elem % 2 == 0 ?
|
|
1663
1709
|
[elem, elem]
|
|
1710
|
+
// return arrays as-is...
|
|
1664
1711
|
: elem instanceof Array ?
|
|
1665
|
-
|
|
1712
|
+
[elem]
|
|
1713
|
+
// remove other elements...
|
|
1666
1714
|
: [] })
|
|
1667
1715
|
.then(function(lst){
|
|
1668
|
-
console.log(lst) // -> [2, 2, 4, 4, [5, 6]]
|
|
1669
|
-
})
|
|
1716
|
+
console.log(lst) }) // -> [2, 2, 4, 4, [5, 6]]
|
|
1670
1717
|
```
|
|
1671
1718
|
|
|
1672
1719
|
|
package/package.json
CHANGED
package/Promise.js.bak
DELETED
|
@@ -1,548 +0,0 @@
|
|
|
1
|
-
/**********************************************************************
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* This defines the following extensions to Promise:
|
|
7
|
-
*
|
|
8
|
-
* Promise.iter(seq)
|
|
9
|
-
* Iterable promise object.
|
|
10
|
-
* Similar to Promise.all(..) but adds basic iterator/generator
|
|
11
|
-
* API and will resolve the items as they are ready (resolved).
|
|
12
|
-
*
|
|
13
|
-
* Promise.interactive(handler)
|
|
14
|
-
* Interactive promise object.
|
|
15
|
-
* This adds a basic message passing API to the promise.
|
|
16
|
-
*
|
|
17
|
-
* Promise.cooperative()
|
|
18
|
-
* Cooperative promise object.
|
|
19
|
-
* Exposes the API to resolve/reject the promise object
|
|
20
|
-
* externally.
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
**********************************************/ /* c8 ignore next 2 */
|
|
25
|
-
((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define)
|
|
26
|
-
(function(require){ var module={} // make module AMD/node compatible...
|
|
27
|
-
/*********************************************************************/
|
|
28
|
-
|
|
29
|
-
var object = require('ig-object')
|
|
30
|
-
|
|
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
|
-
|
|
44
|
-
|
|
45
|
-
//---------------------------------------------------------------------
|
|
46
|
-
// Iterable promise...
|
|
47
|
-
//
|
|
48
|
-
// Like Promise.all(..) but adds ability to iterate through results
|
|
49
|
-
// via generators .map(..)/.reduce(..) and friends...
|
|
50
|
-
//
|
|
51
|
-
|
|
52
|
-
var IterablePromise =
|
|
53
|
-
module.IterablePromise =
|
|
54
|
-
object.Constructor('IterablePromise', Promise, {
|
|
55
|
-
// XXX
|
|
56
|
-
//STOP: object.STOP,
|
|
57
|
-
|
|
58
|
-
//
|
|
59
|
-
// Format:
|
|
60
|
-
// [
|
|
61
|
-
// [ <value> ],
|
|
62
|
-
// <promise>,
|
|
63
|
-
// ...
|
|
64
|
-
// ]
|
|
65
|
-
//
|
|
66
|
-
__list: null,
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
// iterator methods...
|
|
70
|
-
//
|
|
71
|
-
// These will return a new IterablePromise instance...
|
|
72
|
-
//
|
|
73
|
-
// When called from a resolved promise these will return a new
|
|
74
|
-
// resolved promise with updated values...
|
|
75
|
-
//
|
|
76
|
-
// When called from a rejected promise these will return a rejected
|
|
77
|
-
// with the same reason promise...
|
|
78
|
-
//
|
|
79
|
-
//
|
|
80
|
-
// NOTE: these are different to Array's equivalents in that the handler
|
|
81
|
-
// is called not in the order of the elements but rather in order
|
|
82
|
-
// of promise resolution...
|
|
83
|
-
// NOTE: index of items is unknowable because items can expand and
|
|
84
|
-
// contract depending on handlrs (e.g. .filter(..) can remove
|
|
85
|
-
// items)...
|
|
86
|
-
// This the following can not be implemented here:
|
|
87
|
-
// .slice(..)
|
|
88
|
-
// .splice(..)
|
|
89
|
-
// .values() / .keys()
|
|
90
|
-
// .at(..)
|
|
91
|
-
// [Symbol.iterator]() - needs to be sync...
|
|
92
|
-
// The followng methods are questionable:
|
|
93
|
-
// .indexOf(..)
|
|
94
|
-
// .includes(..)
|
|
95
|
-
// .some(..) / .every(..)
|
|
96
|
-
// .sort(..)
|
|
97
|
-
// XXX BUG:
|
|
98
|
-
// Promise.iter([1,2,3])
|
|
99
|
-
// .map(e => e)
|
|
100
|
-
// is not the same as:
|
|
101
|
-
// Promise.iter([1,2,3])
|
|
102
|
-
// .map(e => e)
|
|
103
|
-
// .map(e => e)
|
|
104
|
-
// XXX should these support STOP???
|
|
105
|
-
map: function(func){
|
|
106
|
-
return this.constructor(this.__list.flat(),
|
|
107
|
-
function(e){
|
|
108
|
-
return [func(e)] }) },
|
|
109
|
-
filter: function(func){
|
|
110
|
-
return this.constructor(this.__list.flat(),
|
|
111
|
-
function(e){
|
|
112
|
-
return func(e) ?
|
|
113
|
-
[e]
|
|
114
|
-
: [] }) },
|
|
115
|
-
// NOTE: this does not return an iterable promise as we can't know
|
|
116
|
-
// what the user reduces to...
|
|
117
|
-
// NOTE: the items can be handled out of order because the nested
|
|
118
|
-
// promises can resolve in any order.
|
|
119
|
-
// XXX write how to go around this...
|
|
120
|
-
// NOTE: since order of execution can not be guaranteed there is no
|
|
121
|
-
// point in implementing .reduceRight(..)
|
|
122
|
-
reduce: function(func, res){
|
|
123
|
-
return this.constructor(this.__list.flat(),
|
|
124
|
-
function(e){
|
|
125
|
-
res = func(res, e)
|
|
126
|
-
return [] })
|
|
127
|
-
.then(function(){
|
|
128
|
-
return res }) },
|
|
129
|
-
flat: function(depth=1){
|
|
130
|
-
return this.constructor(this.__list.flat(),
|
|
131
|
-
function(e){
|
|
132
|
-
return (depth > 1
|
|
133
|
-
&& e != null
|
|
134
|
-
&& e.flat) ?
|
|
135
|
-
e.flat(depth-1)
|
|
136
|
-
: depth != 0 ?
|
|
137
|
-
e
|
|
138
|
-
: [e] }) },
|
|
139
|
-
// XXX REVERSE...
|
|
140
|
-
// XXX BUG:
|
|
141
|
-
// await Promise.iter([1, Promise.iter(['a', ['b', 'c']]), [2, 3], 4])
|
|
142
|
-
// .flat()
|
|
143
|
-
// -> [ 1, 'a', [ 'b', 'c' ], 2, 3, 4 ]
|
|
144
|
-
// await Promise.iter([1, Promise.iter(['a', ['b', 'c']]), [2, 3], 4])
|
|
145
|
-
// .flat()
|
|
146
|
-
// .reverse()
|
|
147
|
-
// -> [ 4, 2, 3, [ 'b', 'c', 'a' ], 1 ]
|
|
148
|
-
// ...should be:
|
|
149
|
-
// -> [ 4, 2, 3, [ 'b', 'c' ], 'a', 1 ]
|
|
150
|
-
// it's odd we are not seeing this in other places...
|
|
151
|
-
reverse: function(){
|
|
152
|
-
return this.constructor(this.__list
|
|
153
|
-
.map(function(elems){
|
|
154
|
-
return elems && elems.then ?
|
|
155
|
-
elems.then(function(res){
|
|
156
|
-
return res
|
|
157
|
-
.reverse()
|
|
158
|
-
.flat() })
|
|
159
|
-
: elems })
|
|
160
|
-
.reverse()
|
|
161
|
-
.flat()) },
|
|
162
|
-
|
|
163
|
-
// compatibility with root promise...
|
|
164
|
-
// XXX BUG:
|
|
165
|
-
// await Promise.iter(Promise.resolve([1,2,[3, 4]])).iter()
|
|
166
|
-
// -> [ [ 1, 2, 3, 4 ] ]
|
|
167
|
-
iter: function(){
|
|
168
|
-
return this.constructor(
|
|
169
|
-
// clone and unwrap the .__list
|
|
170
|
-
this.__list
|
|
171
|
-
.map(function(elems){
|
|
172
|
-
return elems && elems.then ?
|
|
173
|
-
elems.then(function(res){
|
|
174
|
-
return res instanceof Array ?
|
|
175
|
-
res.flat()
|
|
176
|
-
: res })
|
|
177
|
-
: elems })
|
|
178
|
-
.flat()) },
|
|
179
|
-
|
|
180
|
-
// XXX do we need these?
|
|
181
|
-
// .pop()
|
|
182
|
-
// .shift()
|
|
183
|
-
// .first() / .last()
|
|
184
|
-
// XXX these can change the "resolved" state...
|
|
185
|
-
// ...i.e. return a pending promise when called from a fulfilled
|
|
186
|
-
// promise....
|
|
187
|
-
// .concat(..)
|
|
188
|
-
// .push(..)
|
|
189
|
-
// .unshift(..)
|
|
190
|
-
// .first(..) / .last(..)
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
// Overload .then(..), .catch(..) and .finally(..) to return a plain
|
|
194
|
-
// Promise instnace...
|
|
195
|
-
//
|
|
196
|
-
// NOTE: .catch(..) and .finally(..) are implemented through .then(..)
|
|
197
|
-
// so we do not need to overload those...
|
|
198
|
-
// NOTE: this is slightly different from .then(..) in that it can be
|
|
199
|
-
// called without arguments and return a promise wrapper. This can
|
|
200
|
-
// be useful to hide special promise functionality...
|
|
201
|
-
then: function (onfulfilled, onrejected){
|
|
202
|
-
var p = new Promise(
|
|
203
|
-
function(resolve, reject){
|
|
204
|
-
Promise.prototype.then.call(this,
|
|
205
|
-
// NOTE: resolve(..) / reject(..) return undefined so
|
|
206
|
-
// we can't pass them directly here...
|
|
207
|
-
function(res){
|
|
208
|
-
resolve(res)
|
|
209
|
-
return res },
|
|
210
|
-
function(res){
|
|
211
|
-
reject(res)
|
|
212
|
-
return res }) }.bind(this))
|
|
213
|
-
return arguments.length > 0 ?
|
|
214
|
-
p.then(...arguments)
|
|
215
|
-
: p },
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
//
|
|
219
|
-
// Promise.iter([ .. ])
|
|
220
|
-
// -> iterable-promise
|
|
221
|
-
//
|
|
222
|
-
// Promise.iter([ .. ], handler)
|
|
223
|
-
// -> iterable-promise
|
|
224
|
-
//
|
|
225
|
-
//
|
|
226
|
-
// handler(e)
|
|
227
|
-
// -> [value]
|
|
228
|
-
// -> []
|
|
229
|
-
//
|
|
230
|
-
//
|
|
231
|
-
// NOTE: element index is unknowable untill the full list is expanded
|
|
232
|
-
// as handler(..)'s return value can expand to any number of
|
|
233
|
-
// items...
|
|
234
|
-
// XXX we can make the index a promise, then if the client needs
|
|
235
|
-
// the value they can wait for it...
|
|
236
|
-
//
|
|
237
|
-
//
|
|
238
|
-
// Spectial cases usefull for extending this constructor...
|
|
239
|
-
//
|
|
240
|
-
// Clone the iterator...
|
|
241
|
-
// Promise.iter([ .. ], false)
|
|
242
|
-
// -> iterable-promise
|
|
243
|
-
//
|
|
244
|
-
// Create a rejected iterator...
|
|
245
|
-
// Promise.iter(false)
|
|
246
|
-
// -> iterable-promise
|
|
247
|
-
//
|
|
248
|
-
//
|
|
249
|
-
// XXX if list is an iterator, can we fill this async???
|
|
250
|
-
// XXX iterator/generator as input:
|
|
251
|
-
// - do we unwind here or externally?
|
|
252
|
-
// ...feels like with the generator external unwinding is
|
|
253
|
-
// needed...
|
|
254
|
-
// XXX would be nice to support trowing STOP...
|
|
255
|
-
// - this is more complicated than simply suing .smap(..) instead
|
|
256
|
-
// of .map(..) because the list can contain async promises...
|
|
257
|
-
// ...would need to wrap each .then(..) call in try-catch and
|
|
258
|
-
// manually handle the stop...
|
|
259
|
-
// - another issue here is that the stop would happen in order of
|
|
260
|
-
// execution and not order of elements...
|
|
261
|
-
// XXX add support for list as a promise....
|
|
262
|
-
__new__: function(_, list, handler){
|
|
263
|
-
// handle: IterablePromise(<list>, <mode>)
|
|
264
|
-
if(typeof(handler) == 'string'){
|
|
265
|
-
mode = handler
|
|
266
|
-
handler = undefined }
|
|
267
|
-
|
|
268
|
-
// instance...
|
|
269
|
-
var promise
|
|
270
|
-
var obj = Reflect.construct(
|
|
271
|
-
IterablePromise.__proto__,
|
|
272
|
-
[function(resolve, reject){
|
|
273
|
-
// NOTE: this is here for Promise compatibilty...
|
|
274
|
-
if(typeof(list) == 'function'){
|
|
275
|
-
return list.call(this, ...arguments) }
|
|
276
|
-
// initial reject...
|
|
277
|
-
if(list === false){
|
|
278
|
-
return reject() }
|
|
279
|
-
promise = {resolve, reject} }],
|
|
280
|
-
IterablePromise)
|
|
281
|
-
|
|
282
|
-
if(promise){
|
|
283
|
-
// clone/normalize...
|
|
284
|
-
list =
|
|
285
|
-
// special case: promised list...
|
|
286
|
-
list instanceof Promise ?
|
|
287
|
-
list.then(function(res){
|
|
288
|
-
return [res] })
|
|
289
|
-
: [list].flat()
|
|
290
|
-
.map(function(e){
|
|
291
|
-
return (e && e.then) ?
|
|
292
|
-
e.then(function(e){
|
|
293
|
-
return [e] })
|
|
294
|
-
: [e] })
|
|
295
|
-
|
|
296
|
-
if(handler){
|
|
297
|
-
// NOTE: this is recursive to handle expanding nested promises...
|
|
298
|
-
var handle = function(elem){
|
|
299
|
-
// call the handler...
|
|
300
|
-
return (elem && elem.then) ?
|
|
301
|
-
elem.then(function(elems){
|
|
302
|
-
return elems
|
|
303
|
-
.map(handle)
|
|
304
|
-
.flat() })
|
|
305
|
-
: elem
|
|
306
|
-
.map(handler)
|
|
307
|
-
.flat() }
|
|
308
|
-
|
|
309
|
-
// handle the list...
|
|
310
|
-
//list = list.map(handle) }
|
|
311
|
-
list =
|
|
312
|
-
list instanceof Promise ?
|
|
313
|
-
// special case: promised list...
|
|
314
|
-
list.then(function(list){
|
|
315
|
-
return list.map(handle) })
|
|
316
|
-
: list.map(handle) }
|
|
317
|
-
|
|
318
|
-
Object.defineProperty(obj, '__list', {
|
|
319
|
-
value: list,
|
|
320
|
-
enumerable: false,
|
|
321
|
-
})
|
|
322
|
-
|
|
323
|
-
// handle promise state...
|
|
324
|
-
//Promise.all(list)
|
|
325
|
-
;(list instanceof Promise ?
|
|
326
|
-
// special case: promised list...
|
|
327
|
-
list
|
|
328
|
-
: Promise.all(list))
|
|
329
|
-
.then(function(res){
|
|
330
|
-
promise.resolve(res.flat()) })
|
|
331
|
-
.catch(promise.reject) }
|
|
332
|
-
|
|
333
|
-
return obj },
|
|
334
|
-
})
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
//---------------------------------------------------------------------
|
|
339
|
-
// Interactive promise...
|
|
340
|
-
//
|
|
341
|
-
// Adds ability to send messages to the running promise.
|
|
342
|
-
//
|
|
343
|
-
|
|
344
|
-
var InteractivePromise =
|
|
345
|
-
module.InteractivePromise =
|
|
346
|
-
object.Constructor('InteractivePromise', Promise, {
|
|
347
|
-
// XXX do we need a way to remove handlers???
|
|
348
|
-
__message_handlers: null,
|
|
349
|
-
|
|
350
|
-
send: function(...args){
|
|
351
|
-
var that = this
|
|
352
|
-
;(this.__message_handlers || [])
|
|
353
|
-
.forEach(function(h){ h.call(that, ...args) })
|
|
354
|
-
return this },
|
|
355
|
-
|
|
356
|
-
then: IterablePromise.prototype.then,
|
|
357
|
-
|
|
358
|
-
//
|
|
359
|
-
// Promise.interactive(handler)
|
|
360
|
-
// -> interacive-promise
|
|
361
|
-
//
|
|
362
|
-
// handler(resolve, reject, onmessage)
|
|
363
|
-
//
|
|
364
|
-
// onmessage(func)
|
|
365
|
-
//
|
|
366
|
-
//
|
|
367
|
-
__new__: function(_, handler){
|
|
368
|
-
var handlers = []
|
|
369
|
-
|
|
370
|
-
var onmessage = function(func){
|
|
371
|
-
// remove all handlers...
|
|
372
|
-
if(func === false){
|
|
373
|
-
var h = (obj == null ?
|
|
374
|
-
handlers
|
|
375
|
-
: (obj.__message_handlers || []))
|
|
376
|
-
h.splice(0, handlers.length)
|
|
377
|
-
// remove a specific handler...
|
|
378
|
-
} else if(arguments[1] === false){
|
|
379
|
-
var h = (obj == null ?
|
|
380
|
-
handlers
|
|
381
|
-
: (obj.__message_handlers || []))
|
|
382
|
-
h.splice(h.indexOf(func), 1)
|
|
383
|
-
// register a handler...
|
|
384
|
-
} else {
|
|
385
|
-
var h = obj == null ?
|
|
386
|
-
// NOTE: we need to get the handlers from .__message_handlers
|
|
387
|
-
// unless we are not fully defined yet, then use the
|
|
388
|
-
// bootstrap container (handlers)...
|
|
389
|
-
// ...since we can call onmessage(..) while the promise
|
|
390
|
-
// is still defined there is no way to .send(..) until it
|
|
391
|
-
// returns a promise object, this races here are highly
|
|
392
|
-
// unlikely...
|
|
393
|
-
handlers
|
|
394
|
-
: (obj.__message_handlers =
|
|
395
|
-
obj.__message_handlers ?? [])
|
|
396
|
-
handlers.push(func) } }
|
|
397
|
-
|
|
398
|
-
var obj = Reflect.construct(
|
|
399
|
-
InteractivePromise.__proto__,
|
|
400
|
-
!handler ?
|
|
401
|
-
[]
|
|
402
|
-
: [function(resolve, reject){
|
|
403
|
-
return handler(resolve, reject, onmessage) }],
|
|
404
|
-
InteractivePromise)
|
|
405
|
-
Object.defineProperty(obj, '__message_handlers', {
|
|
406
|
-
value: handlers,
|
|
407
|
-
enumerable: false,
|
|
408
|
-
// XXX should this be .configurable???
|
|
409
|
-
configurable: true,
|
|
410
|
-
})
|
|
411
|
-
return obj },
|
|
412
|
-
})
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
//---------------------------------------------------------------------
|
|
417
|
-
// Cooperative promise...
|
|
418
|
-
//
|
|
419
|
-
// A promise that can be resolved/rejected externally.
|
|
420
|
-
// NOTE: normally this has no internal resolver logic...
|
|
421
|
-
//
|
|
422
|
-
|
|
423
|
-
var CooperativePromise =
|
|
424
|
-
module.CooperativePromise =
|
|
425
|
-
object.Constructor('CooperativePromise', Promise, {
|
|
426
|
-
__handlers: null,
|
|
427
|
-
|
|
428
|
-
get isSet(){
|
|
429
|
-
return this.__handlers === false },
|
|
430
|
-
|
|
431
|
-
set: function(value, resolve=true){
|
|
432
|
-
// can't set twice...
|
|
433
|
-
if(this.isSet){
|
|
434
|
-
throw new Error('.set(..): can not set twice') }
|
|
435
|
-
// bind to promise...
|
|
436
|
-
if(value && value.then && value.catch){
|
|
437
|
-
value.then(handlers.resolve)
|
|
438
|
-
value.catch(handlers.reject)
|
|
439
|
-
// resolve with value...
|
|
440
|
-
} else {
|
|
441
|
-
resolve ?
|
|
442
|
-
this.__handlers.resolve(value)
|
|
443
|
-
: this.__handlers.reject(value) }
|
|
444
|
-
// cleanup and prevent setting twice...
|
|
445
|
-
this.__handlers = false
|
|
446
|
-
return this },
|
|
447
|
-
|
|
448
|
-
then: IterablePromise.prototype.then,
|
|
449
|
-
|
|
450
|
-
__new__: function(){
|
|
451
|
-
var handlers
|
|
452
|
-
var resolver = arguments[1]
|
|
453
|
-
|
|
454
|
-
var obj = Reflect.construct(
|
|
455
|
-
CooperativePromise.__proto__,
|
|
456
|
-
[function(resolve, reject){
|
|
457
|
-
handlers = {resolve, reject}
|
|
458
|
-
// NOTE: this is here to support builtin .then(..)
|
|
459
|
-
resolver
|
|
460
|
-
&& resolver(resolve, reject) }],
|
|
461
|
-
CooperativePromise)
|
|
462
|
-
|
|
463
|
-
Object.defineProperty(obj, '__handlers', {
|
|
464
|
-
value: handlers,
|
|
465
|
-
enumerable: false,
|
|
466
|
-
writable: true,
|
|
467
|
-
})
|
|
468
|
-
return obj },
|
|
469
|
-
})
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
//---------------------------------------------------------------------
|
|
474
|
-
|
|
475
|
-
// XXX EXPEREMENTAL...
|
|
476
|
-
var ProxyPromise =
|
|
477
|
-
module.ProxyPromise =
|
|
478
|
-
object.Constructor('ProxyPromise', Promise, {
|
|
479
|
-
__new__: function(context, constructor){
|
|
480
|
-
var proto = 'prototype' in constructor ?
|
|
481
|
-
constructor.prototype
|
|
482
|
-
: constructor
|
|
483
|
-
var obj = Reflect.construct(
|
|
484
|
-
ProxyPromise.__proto__,
|
|
485
|
-
[function(resolve, reject){
|
|
486
|
-
context.then(resolve)
|
|
487
|
-
context.catch(reject) }],
|
|
488
|
-
ProxyPromise)
|
|
489
|
-
// populate...
|
|
490
|
-
// NOTE: we are not using object.deepKeys(..) here as we need
|
|
491
|
-
// the key origin not to trigger property getters...
|
|
492
|
-
var seen = new Set()
|
|
493
|
-
while(proto != null){
|
|
494
|
-
Object.entries(Object.getOwnPropertyDescriptors(proto))
|
|
495
|
-
.forEach(function([key, value]){
|
|
496
|
-
// skip overloaded keys...
|
|
497
|
-
if(seen.has(key)){
|
|
498
|
-
return }
|
|
499
|
-
// skip non-functions...
|
|
500
|
-
if(typeof(value.value) != 'function'){
|
|
501
|
-
return }
|
|
502
|
-
// skip non-enumerable except for Object.prototype.run(..)...
|
|
503
|
-
if(!(key == 'run'
|
|
504
|
-
&& Object.prototype.run === value.value)
|
|
505
|
-
&& !value.enumerable){
|
|
506
|
-
return }
|
|
507
|
-
// proxy...
|
|
508
|
-
obj[key] = function(...args){
|
|
509
|
-
// XXX should we also .catch(..) here???
|
|
510
|
-
return context.then(function(res){
|
|
511
|
-
return res[key](...args) }) } })
|
|
512
|
-
proto = proto.__proto__ }
|
|
513
|
-
return obj },
|
|
514
|
-
})
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
//---------------------------------------------------------------------
|
|
519
|
-
|
|
520
|
-
var PromiseMixin =
|
|
521
|
-
module.PromiseMixin =
|
|
522
|
-
object.Mixin('PromiseMixin', 'soft', {
|
|
523
|
-
iter: IterablePromise,
|
|
524
|
-
interactive: InteractivePromise,
|
|
525
|
-
cooperative: CooperativePromise,
|
|
526
|
-
})
|
|
527
|
-
|
|
528
|
-
PromiseMixin(Promise)
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
// XXX EXPEREMENTAL...
|
|
532
|
-
var PromiseProtoMixin =
|
|
533
|
-
module.PromiseProtoMixin =
|
|
534
|
-
object.Mixin('PromiseProtoMixin', 'soft', {
|
|
535
|
-
as: ProxyPromise,
|
|
536
|
-
|
|
537
|
-
// XXX
|
|
538
|
-
iter: function(){
|
|
539
|
-
return IterablePromise(this) },
|
|
540
|
-
})
|
|
541
|
-
|
|
542
|
-
PromiseProtoMixin(Promise.prototype)
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
/**********************************************************************
|
|
548
|
-
* vim:set ts=4 sw=4 : */ return module })
|