1
- import { getGlobal } from '../prebidGlobal.js' ;
2
-
3
1
const SUCCESS = 0 ;
4
2
const FAIL = 1 ;
5
3
6
4
/**
7
5
* A version of Promise that runs callbacks synchronously when it can (i.e. after it's been fulfilled or rejected).
8
6
*/
9
- export class GreedyPromise extends ( getGlobal ( ) . Promise || Promise ) {
7
+ export class GreedyPromise {
10
8
#result;
11
9
#callbacks;
12
- #parent = null ;
13
10
14
11
/**
15
12
* Convenience wrapper for setTimeout; takes care of returning an already fulfilled GreedyPromise when the delay is zero.
@@ -24,53 +21,33 @@ export class GreedyPromise extends (getGlobal().Promise || Promise) {
24
21
}
25
22
26
23
constructor ( resolver ) {
24
+ if ( typeof resolver !== 'function' ) {
25
+ throw new Error ( 'resolver not a function' ) ;
26
+ }
27
27
const result = [ ] ;
28
28
const callbacks = [ ] ;
29
- function handler ( type , resolveFn ) {
29
+ let [ resolve , reject ] = [ SUCCESS , FAIL ] . map ( ( type ) => {
30
30
return function ( value ) {
31
- if ( ! result . length ) {
31
+ if ( type === SUCCESS && typeof value ?. then === 'function' ) {
32
+ value . then ( resolve , reject ) ;
33
+ } else if ( ! result . length ) {
32
34
result . push ( type , value ) ;
33
35
while ( callbacks . length ) callbacks . shift ( ) ( ) ;
34
- resolveFn ( value ) ;
35
36
}
36
37
}
38
+ } ) ;
39
+ try {
40
+ resolver ( resolve , reject ) ;
41
+ } catch ( e ) {
42
+ reject ( e ) ;
37
43
}
38
- super (
39
- typeof resolver !== 'function'
40
- ? resolver // let super throw an error
41
- : ( resolve , reject ) => {
42
- const rejectHandler = handler ( FAIL , reject ) ;
43
- const resolveHandler = ( ( ) => {
44
- const done = handler ( SUCCESS , resolve ) ;
45
- return value =>
46
- typeof value ?. then === 'function' ? value . then ( done , rejectHandler ) : done ( value ) ;
47
- } ) ( ) ;
48
- try {
49
- resolver ( resolveHandler , rejectHandler ) ;
50
- } catch ( e ) {
51
- rejectHandler ( e ) ;
52
- }
53
- }
54
- ) ;
55
44
this . #result = result ;
56
45
this . #callbacks = callbacks ;
57
46
}
47
+
58
48
then ( onSuccess , onError ) {
59
- if ( typeof onError === 'function' ) {
60
- // if an error handler is provided, attach a dummy error handler to super,
61
- // and do the same for all promises without an error handler that precede this one in a chain.
62
- // This is to avoid unhandled rejection events / warnings for errors that were, in fact, handled;
63
- // since we are not using super's callback mechanisms we need to make it aware of this separately.
64
- let node = this ;
65
- while ( node ) {
66
- super . then . call ( node , null , ( ) => null ) ;
67
- const next = node . #parent;
68
- node . #parent = null ; // since we attached a handler already, we are no longer interested in what will happen later in the chain
69
- node = next ;
70
- }
71
- }
72
49
const result = this . #result;
73
- const res = new GreedyPromise ( ( resolve , reject ) => {
50
+ return new this . constructor ( ( resolve , reject ) => {
74
51
const continuation = ( ) => {
75
52
let value = result [ 1 ] ;
76
53
let [ handler , resolveFn ] = result [ 0 ] === SUCCESS ? [ onSuccess , resolve ] : [ onError , reject ] ;
@@ -87,8 +64,50 @@ export class GreedyPromise extends (getGlobal().Promise || Promise) {
87
64
}
88
65
result . length ? continuation ( ) : this . #callbacks. push ( continuation ) ;
89
66
} ) ;
90
- res . #parent = this ;
91
- return res ;
67
+ }
68
+
69
+ catch ( onError ) {
70
+ return this . then ( null , onError ) ;
71
+ }
72
+
73
+ finally ( onFinally ) {
74
+ let val ;
75
+ return this . then (
76
+ ( v ) => { val = v ; return onFinally ( ) ; } ,
77
+ ( e ) => { val = this . constructor . reject ( e ) ; return onFinally ( ) }
78
+ ) . then ( ( ) => val ) ;
79
+ }
80
+
81
+ static #collect( promises , collector , done ) {
82
+ let cnt = promises . length ;
83
+ function clt ( ) {
84
+ collector . apply ( this , arguments ) ;
85
+ if ( -- cnt === 0 && done ) done ( ) ;
86
+ }
87
+ promises . forEach ( ( p , i ) => this . resolve ( p ) . then (
88
+ ( val ) => clt ( true , val , i ) ,
89
+ ( err ) => clt ( false , err , i )
90
+ ) ) ;
91
+ }
92
+
93
+ static race ( promises ) {
94
+ return new this ( ( resolve , reject ) => {
95
+ this . #collect( promises , ( success , result ) => success ? resolve ( result ) : reject ( result ) ) ;
96
+ } )
97
+ }
98
+
99
+ static all ( promises ) {
100
+ return new this ( ( resolve , reject ) => {
101
+ let res = [ ] ;
102
+ this . #collect( promises , ( success , val , i ) => success ? res [ i ] = val : reject ( val ) , ( ) => resolve ( res ) ) ;
103
+ } )
104
+ }
105
+
106
+ static allSettled ( promises ) {
107
+ return new this ( ( resolve ) => {
108
+ let res = [ ] ;
109
+ this . #collect( promises , ( success , val , i ) => res [ i ] = success ? { status : 'fulfilled' , value : val } : { status : 'rejected' , reason : val } , ( ) => resolve ( res ) )
110
+ } )
92
111
}
93
112
94
113
static resolve ( value ) {
0 commit comments