@@ -49,6 +49,8 @@ export class AsyncState<T, E, R> implements StateInterface<T, E, R> {
49
49
private locks ?: number ;
50
50
isEmitting ?: boolean ;
51
51
52
+ readonly producer : ProducerFunction < T , E , R > ;
53
+
52
54
53
55
//endregion
54
56
@@ -81,7 +83,6 @@ export class AsyncState<T, E, R> implements StateInterface<T, E, R> {
81
83
this . abort = this . abort . bind ( this ) ;
82
84
this . getState = this . getState . bind ( this ) ;
83
85
this . setState = this . setState . bind ( this ) ;
84
- this . producer = this . producer . bind ( this ) ;
85
86
this . subscribe = this . subscribe . bind ( this ) ;
86
87
this . getPayload = this . getPayload . bind ( this ) ;
87
88
this . mergePayload = this . mergePayload . bind ( this ) ;
@@ -96,6 +97,17 @@ export class AsyncState<T, E, R> implements StateInterface<T, E, R> {
96
97
this . invalidateCache = this . invalidateCache . bind ( this ) ;
97
98
this . replaceProducer = this . replaceProducer . bind ( this ) ;
98
99
100
+ let instance = this ;
101
+ this . producer = producerWrapper . bind ( null , {
102
+ setProducerType : ( type : ProducerType ) => instance . producerType = type ,
103
+ setState : instance . setState ,
104
+ getState : instance . getState ,
105
+ instance : instance ,
106
+ setSuspender : ( suspender : Promise < T > ) => instance . suspender = suspender ,
107
+ replaceState : instance . replaceState . bind ( instance ) ,
108
+ getProducer : ( ) => instance . originalProducer ,
109
+ } ) ;
110
+
99
111
this . _source = makeSource ( this ) ;
100
112
101
113
if ( __DEV__ ) {
@@ -120,120 +132,7 @@ export class AsyncState<T, E, R> implements StateInterface<T, E, R> {
120
132
Object . assign ( this . config , partialConfig ) ;
121
133
}
122
134
123
- producer (
124
- props : ProducerProps < T , E , R > ,
125
- indicators : RunIndicators ,
126
- callbacks ?: ProducerCallbacks < T , E , R > ,
127
- ) : AbortFn {
128
- let instance = this ;
129
- const currentProducer = this . originalProducer ;
130
- if ( ! isFunction ( currentProducer ) ) {
131
- indicators . fulfilled = true ;
132
- instance . producerType = ProducerType . notProvided ;
133
- instance . setState ( props . args [ 0 ] , props . args [ 1 ] ) ;
134
- if ( callbacks ) {
135
- switch ( instance . state . status ) {
136
- case Status . success : {
137
- callbacks . onSuccess ?.( instance . state ) ;
138
- break ;
139
- }
140
- case Status . aborted : {
141
- callbacks . onAborted ?.( instance . state ) ;
142
- break ;
143
- }
144
- case Status . error : {
145
- callbacks . onError ?.( instance . state ) ;
146
- break ;
147
- }
148
- }
149
- }
150
- return ;
151
- }
152
- // the running promise is used to pass the status to pending and as suspender in react18+
153
- let runningPromise ;
154
- // the execution value is the return of the initial producer function
155
- let executionValue ;
156
- // it is important to clone to capture properties and save only serializable stuff
157
- const savedProps = cloneProducerProps ( props ) ;
158
-
159
- try {
160
- executionValue = currentProducer ! ( props ) ;
161
- if ( indicators . aborted ) {
162
- return ;
163
- }
164
- } catch ( e ) {
165
- if ( indicators . aborted ) {
166
- return ;
167
- }
168
- if ( __DEV__ ) devtools . emitRunSync ( instance , savedProps ) ;
169
- indicators . fulfilled = true ;
170
- let errorState = StateBuilder . error < T , E > ( e , savedProps ) ;
171
- instance . replaceState ( errorState ) ;
172
- callbacks ?. onError ?.( errorState ) ;
173
- return ;
174
- }
175
135
176
- if ( isGenerator ( executionValue ) ) {
177
- instance . producerType = ProducerType . generator ;
178
- if ( __DEV__ ) devtools . emitRunGenerator ( instance , savedProps ) ;
179
- // generatorResult is either {done, value} or a promise
180
- let generatorResult ;
181
- try {
182
- generatorResult = wrapStartedGenerator ( executionValue , props , indicators ) ;
183
- } catch ( e ) {
184
- indicators . fulfilled = true ;
185
- let errorState = StateBuilder . error < T , E > ( e , savedProps ) ;
186
- instance . replaceState ( errorState ) ;
187
- callbacks ?. onError ?.( errorState ) ;
188
- return ;
189
- }
190
- if ( generatorResult . done ) {
191
- indicators . fulfilled = true ;
192
- let successState = StateBuilder . success ( generatorResult . value , savedProps ) ;
193
- instance . replaceState ( successState ) ;
194
- callbacks ?. onSuccess ?.( successState ) ;
195
- return ;
196
- } else {
197
- runningPromise = generatorResult ;
198
- instance . suspender = runningPromise ;
199
- instance . replaceState ( StateBuilder . pending ( savedProps ) ) ;
200
- }
201
- } else if ( isPromise ( executionValue ) ) {
202
- instance . producerType = ProducerType . promise ;
203
- if ( __DEV__ ) devtools . emitRunPromise ( instance , savedProps ) ;
204
- runningPromise = executionValue ;
205
- instance . suspender = runningPromise ;
206
- instance . replaceState ( StateBuilder . pending ( savedProps ) ) ;
207
- } else { // final value
208
- if ( __DEV__ ) devtools . emitRunSync ( instance , savedProps ) ;
209
- indicators . fulfilled = true ;
210
- instance . producerType = ProducerType . sync ;
211
- let successState = StateBuilder . success ( executionValue , savedProps ) ;
212
- instance . replaceState ( successState ) ;
213
- callbacks ?. onSuccess ?.( successState ) ;
214
- return ;
215
- }
216
-
217
- runningPromise
218
- . then ( stateData => {
219
- let aborted = indicators . aborted ;
220
- if ( ! aborted ) {
221
- indicators . fulfilled = true ;
222
- let successState = StateBuilder . success ( stateData , savedProps ) ;
223
- instance . replaceState ( successState ) ;
224
- callbacks ?. onSuccess ?.( successState ) ;
225
- }
226
- } )
227
- . catch ( stateError => {
228
- let aborted = indicators . aborted ;
229
- if ( ! aborted ) {
230
- indicators . fulfilled = true ;
231
- let errorState = StateBuilder . error < T , E > ( stateError , savedProps ) ;
232
- instance . replaceState ( errorState ) ;
233
- callbacks ?. onError ?.( errorState ) ;
234
- }
235
- } ) ;
236
- } ;
237
136
238
137
getPayload ( ) : Record < string , any > {
239
138
if ( ! this . payload ) {
@@ -714,7 +613,133 @@ export class AsyncState<T, E, R> implements StateInterface<T, E, R> {
714
613
715
614
//region AsyncState methods helpers
716
615
717
- function cloneProducerProps < T , E , R > ( props : ProducerProps < T , E , R > ) : ProducerSavedProps < T > {
616
+ export type ProducerWrapperInput < T , E , R > = {
617
+ setProducerType ( type : ProducerType ) : void ,
618
+ setState : StateUpdater < T , E , R > ,
619
+ getState ( ) : State < T , E , R > ,
620
+ instance ?: StateInterface < T , E , R > ,
621
+ setSuspender ( p : Promise < T > ) : void ,
622
+ replaceState ( newState : State < T , E , R > , notify ?: boolean ) ,
623
+ getProducer ( ) : Producer < T , E , R > | undefined | null ,
624
+ }
625
+ export function producerWrapper < T , E = any , R = any > (
626
+ input : ProducerWrapperInput < T , E , R > ,
627
+ props : ProducerProps < T , E , R > ,
628
+ indicators : RunIndicators ,
629
+ callbacks ?: ProducerCallbacks < T , E , R > ,
630
+ ) : AbortFn {
631
+ const currentProducer = input . getProducer ( ) ;
632
+ if ( ! isFunction ( currentProducer ) ) {
633
+ indicators . fulfilled = true ;
634
+ input . setProducerType ( ProducerType . notProvided ) ;
635
+ input . setState ( props . args [ 0 ] , props . args [ 1 ] ) ;
636
+
637
+ if ( callbacks ) {
638
+ let currentState = input . getState ( ) ;
639
+ switch ( currentState . status ) {
640
+ case Status . success : {
641
+ callbacks . onSuccess ?.( currentState ) ;
642
+ break ;
643
+ }
644
+ case Status . aborted : {
645
+ callbacks . onAborted ?.( currentState ) ;
646
+ break ;
647
+ }
648
+ case Status . error : {
649
+ callbacks . onError ?.( currentState ) ;
650
+ break ;
651
+ }
652
+ }
653
+ }
654
+ return ;
655
+ }
656
+ // the running promise is used to pass the status to pending and as suspender in react18+
657
+ let runningPromise ;
658
+ // the execution value is the return of the initial producer function
659
+ let executionValue ;
660
+ // it is important to clone to capture properties and save only serializable stuff
661
+ const savedProps = cloneProducerProps ( props ) ;
662
+
663
+ try {
664
+ executionValue = currentProducer ! ( props ) ;
665
+ if ( indicators . aborted ) {
666
+ return ;
667
+ }
668
+ } catch ( e ) {
669
+ if ( indicators . aborted ) {
670
+ return ;
671
+ }
672
+ if ( __DEV__ && input . instance ) devtools . emitRunSync ( input . instance , savedProps ) ;
673
+ indicators . fulfilled = true ;
674
+ let errorState = StateBuilder . error < T , E > ( e , savedProps ) ;
675
+ input . replaceState ( errorState ) ;
676
+ callbacks ?. onError ?.( errorState ) ;
677
+ return ;
678
+ }
679
+
680
+ if ( isGenerator ( executionValue ) ) {
681
+ input . setProducerType ( ProducerType . generator ) ;
682
+ if ( __DEV__ && input . instance ) devtools . emitRunGenerator ( input . instance , savedProps ) ;
683
+ // generatorResult is either {done, value} or a promise
684
+ let generatorResult ;
685
+ try {
686
+ generatorResult = wrapStartedGenerator ( executionValue , props , indicators ) ;
687
+ } catch ( e ) {
688
+ indicators . fulfilled = true ;
689
+ let errorState = StateBuilder . error < T , E > ( e , savedProps ) ;
690
+ input . replaceState ( errorState ) ;
691
+ callbacks ?. onError ?.( errorState ) ;
692
+ return ;
693
+ }
694
+ if ( generatorResult . done ) {
695
+ indicators . fulfilled = true ;
696
+ let successState = StateBuilder . success ( generatorResult . value , savedProps ) ;
697
+ input . replaceState ( successState ) ;
698
+ callbacks ?. onSuccess ?.( successState ) ;
699
+ return ;
700
+ } else {
701
+ runningPromise = generatorResult ;
702
+ input . setSuspender ( runningPromise ) ;
703
+ input . replaceState ( StateBuilder . pending ( savedProps ) ) ;
704
+ }
705
+ } else if ( isPromise ( executionValue ) ) {
706
+ input . setProducerType ( ProducerType . promise ) ;
707
+ if ( __DEV__ && input . instance ) devtools . emitRunPromise ( input . instance , savedProps ) ;
708
+ runningPromise = executionValue ;
709
+ input . setSuspender ( runningPromise ) ;
710
+ input . replaceState ( StateBuilder . pending ( savedProps ) ) ;
711
+ } else { // final value
712
+ if ( __DEV__ && input . instance ) devtools . emitRunSync ( input . instance , savedProps ) ;
713
+ indicators . fulfilled = true ;
714
+ input . setProducerType ( ProducerType . sync ) ;
715
+ let successState = StateBuilder . success ( executionValue , savedProps ) ;
716
+ input . replaceState ( successState ) ;
717
+ callbacks ?. onSuccess ?.( successState ) ;
718
+ return ;
719
+ }
720
+
721
+ runningPromise
722
+ . then ( stateData => {
723
+ let aborted = indicators . aborted ;
724
+ if ( ! aborted ) {
725
+ indicators . fulfilled = true ;
726
+ let successState = StateBuilder . success ( stateData , savedProps ) ;
727
+ input . replaceState ( successState ) ;
728
+ callbacks ?. onSuccess ?.( successState ) ;
729
+ }
730
+ } )
731
+ . catch ( stateError => {
732
+ let aborted = indicators . aborted ;
733
+ if ( ! aborted ) {
734
+ indicators . fulfilled = true ;
735
+ let errorState = StateBuilder . error < T , E > ( stateError , savedProps ) ;
736
+ input . replaceState ( errorState ) ;
737
+ callbacks ?. onError ?.( errorState ) ;
738
+ }
739
+ } ) ;
740
+ }
741
+
742
+ export function cloneProducerProps < T , E , R > ( props : ProducerProps < T , E , R > ) : ProducerSavedProps < T > {
718
743
const output : ProducerSavedProps < T > = {
719
744
lastSuccess : shallowClone ( props . lastSuccess ) ,
720
745
payload : props . payload ,
0 commit comments