1
+ function runPromises ( items , props = { } ) {
2
+ return new Promise ( ( resolve , reject ) => {
3
+ let pending = items . length ;
4
+ if ( pending == 0 ) resolve ( ) ;
5
+ function checkAndResolve ( value ) {
6
+ pending -- ;
7
+ if ( pending == 0 ) resolve ( value ) ;
8
+ }
9
+ items . forEach ( promise => {
10
+ promise . promise ( props ) . then ( value => {
11
+ checkAndResolve ( value ) ;
12
+ return value ;
13
+ } ) . catch ( error => {
14
+ if ( promise . critical ) {
15
+ reject ( error ) ;
16
+ } else {
17
+ checkAndResolve ( error ) ;
18
+ }
19
+ throw error ;
20
+ } )
21
+ } ) ;
22
+ } ) ;
23
+ }
24
+
25
+ export interface Options {
26
+ errorHandler ?: Function
27
+ }
28
+
29
+ export class Data {
30
+ private keys : Object ;
31
+ constructor ( ) {
32
+ this . keys = { } ;
33
+ }
34
+ set ( key : string , value ) {
35
+ if ( key in this . keys && value in this . keys [ key ] ) {
36
+ console . warn ( `Value: ${ this . keys [ key ] . value } is already set to key: ${ key } in data. You try to set value: ${ value } ` ) ;
37
+ } else {
38
+ if ( key in this . keys ) {
39
+ this . keys [ key ] . value = value ;
40
+ } else {
41
+ this . keys [ key ] = { value }
42
+ }
43
+ }
44
+ }
45
+ setInitVal ( key : string , initVal ) {
46
+ if ( key in this . keys && initVal in this . keys [ key ] ) {
47
+ console . warn ( `Initial Value: ${ this . keys [ key ] . initVal } is already set to key: ${ key } in data. . You try to set initial value: ${ initVal } ` ) ;
48
+ } else {
49
+ if ( key in this . keys ) {
50
+ this . keys [ key ] . initVal = initVal ;
51
+ } else {
52
+ this . keys [ key ] = { initVal }
53
+ }
54
+ }
55
+ }
56
+ get ( key : string ) {
57
+ if ( key in this . keys ) {
58
+ return this . keys [ key ] . value ? this . keys [ key ] . value : this . keys [ key ] . initVal ;
59
+ } else {
60
+ return null ;
61
+ }
62
+ }
63
+ }
64
+
65
+ export default function hookFetcher ( options : Options = { } ) {
66
+ return {
67
+ start : ( { ctx } ) => {
68
+ ctx . set ( 'fetcher' , {
69
+ items : [ ] ,
70
+ deferred : [ ] ,
71
+ data : new Data ( )
72
+ } ) ;
73
+ } ,
74
+ resolve : async ( { ctx, params } ) => {
75
+ // filter deferred items
76
+ ctx . get ( 'fetcher' ) . deferred = ctx . get ( 'fetcher' ) . items . filter ( item => item . deferred ) ;
77
+ let items = ctx . get ( 'fetcher' ) . items . filter ( item => ! item . deferred ) ;
78
+ // execute promises and return result
79
+ try {
80
+ await runPromises ( items , { params } ) ;
81
+ } catch ( error ) {
82
+ if ( options . errorHandler ) {
83
+ options . errorHandler ( error ) ;
84
+ } else {
85
+ console . error ( 'Hook fetcher resolve error' , error ) ;
86
+ throw error ;
87
+ }
88
+ }
89
+ } ,
90
+ render : async ( { ctx, params, result } ) => {
91
+ if ( ctx . get ( 'fetcher' ) . deferred . length ) {
92
+ try {
93
+ await runPromises ( ctx . get ( 'fetcher' ) . deferred , { params } ) ;
94
+ if ( ctx . get ( 'fetcher' ) . callback ) ctx . get ( 'fetcher' ) . callback ( ) ;
95
+ } catch ( error ) {
96
+ if ( options . errorHandler ) {
97
+ options . errorHandler ( error ) ;
98
+ } else {
99
+ console . error ( 'Hook fetcher render error' , error ) ;
100
+ throw error ;
101
+ }
102
+ }
103
+ }
104
+ }
105
+ }
106
+ }
0 commit comments