1
- const { useEffect, useCallback , useRef, useState} = require ( "react" ) ;
1
+ const { useEffect, useMemo , useRef, useState} = require ( "react" ) ;
2
2
const { CPromise, CanceledError, E_REASON_UNMOUNTED } = require ( "c-promise2" ) ;
3
3
const isEqualObjects = require ( 'is-equal-objects/dist/is-equal-objects.cjs' ) ;
4
4
@@ -166,11 +166,20 @@ const useAsyncCallback = (generator, options) => {
166
166
throw TypeError ( 'options must be an object or array' ) ;
167
167
}
168
168
169
+ const initialState = {
170
+ done : false ,
171
+ result : undefined ,
172
+ error : undefined ,
173
+ canceled : false ,
174
+ pending : false
175
+ } ;
176
+
169
177
const { current} = useRef ( {
170
178
promises : [ ] ,
171
179
queue : [ ] ,
172
180
pending : 0 ,
173
- args : null
181
+ args : null ,
182
+ state : initialState
174
183
} ) ;
175
184
176
185
let {
@@ -200,115 +209,123 @@ const useAsyncCallback = (generator, options) => {
200
209
throw Error ( 'queueSize must be a finite number >=-1' ) ;
201
210
}
202
211
203
- const [ state , setState ] = states ? useState ( {
204
- done : false ,
205
- result : undefined ,
206
- error : undefined ,
207
- canceled : false ,
208
- pending : false
209
- } ) : [ ] ;
212
+ const [ state , setState ] = states ? useState ( initialState ) : [ ] ;
213
+
214
+ const setDeepState = ( newState ) => {
215
+ if ( isEqualObjects ( current . state , newState ) ) return ;
216
+ setState ( newState ) ;
217
+ current . state = newState ;
218
+ }
210
219
211
220
const singleThreaded = threads === 1 ;
212
221
213
- const callback = useCallback ( ( ...args ) => {
214
- const { promises, queue} = current ;
215
- let n ;
216
-
217
- if ( combine && ( n = promises . length ) ) {
218
- let promise ;
219
- while ( n -- > 0 ) {
220
- promise = promises [ n ] ;
221
- if ( argsToPromiseMap . has ( promise ) && isEqualObjects ( argsToPromiseMap . get ( promise ) , args ) ) {
222
- if ( cancelPrevious ) {
223
- promise . cancel ( E_REASON_RESTART ) ;
224
- break ;
222
+ const callback = useMemo ( ( ) => {
223
+ const cancel = ( reason ) => {
224
+ const _reason = isEvent ( reason ) ? undefined : reason ;
225
+ current . promises . forEach ( promise => promise . cancel ( _reason ) ) ;
226
+ current . promises . length = 0 ;
227
+ } ;
228
+
229
+ const fn = ( ...args ) => {
230
+ const { promises, queue} = current ;
231
+ let n ;
232
+
233
+ if ( combine && ( n = promises . length ) ) {
234
+ let promise ;
235
+ while ( n -- > 0 ) {
236
+ promise = promises [ n ] ;
237
+ if ( argsToPromiseMap . has ( promise ) && isEqualObjects ( argsToPromiseMap . get ( promise ) , args ) ) {
238
+ if ( cancelPrevious ) {
239
+ promise . cancel ( E_REASON_RESTART ) ;
240
+ break ;
241
+ }
242
+ return CPromise . resolve ( promise ) ;
225
243
}
226
- return CPromise . resolve ( promise ) ;
227
244
}
228
245
}
229
- }
230
246
231
- const resolveGenerator = ( ) => CPromise . run ( generator , { args, resolveSignatures : true , scopeArg} ) ;
247
+ const resolveGenerator = ( ) => CPromise . run ( generator , { args, resolveSignatures : true , scopeArg} ) ;
232
248
233
- cancelPrevious && ! combine && cancel ( E_REASON_RESTART ) ;
249
+ cancelPrevious && ! combine && cancel ( E_REASON_RESTART ) ;
234
250
235
- if ( threads || queueSize !== - 1 ) {
236
- let started ;
251
+ if ( threads || queueSize !== - 1 ) {
252
+ let started ;
237
253
238
- let promise = new CPromise ( resolve => {
239
- const start = ( ) => {
240
- current . pending ++ ;
254
+ let promise = new CPromise ( resolve => {
255
+ const start = ( ) => {
256
+ current . pending ++ ;
241
257
242
- started = true ;
258
+ started = true ;
243
259
244
- if ( states && singleThreaded ) {
245
- setState ( {
246
- done : false ,
247
- pending : true ,
248
- canceled : false
249
- } )
260
+ if ( states && singleThreaded ) {
261
+ setDeepState ( {
262
+ ...initialState ,
263
+ pending : true ,
264
+ } )
265
+ }
266
+ resolve ( ) ;
250
267
}
251
- resolve ( ) ;
252
- }
253
268
254
- if ( current . pending === threads ) {
255
- if ( queueSize !== - 1 && queue . length === queueSize ) {
256
- throw CanceledError . from ( E_REASON_QUEUE_OVERFLOW ) ;
257
- }
269
+ if ( current . pending === threads ) {
270
+ if ( queueSize !== - 1 && queue . length === queueSize ) {
271
+ throw CanceledError . from ( E_REASON_QUEUE_OVERFLOW ) ;
272
+ }
258
273
259
- return queue . push ( start ) ;
260
- }
274
+ return queue . push ( start ) ;
275
+ }
261
276
262
- start ( ) ;
263
- } ) . weight ( 0 )
264
- . then ( resolveGenerator )
265
- [ catchErrors ? 'done' : 'finally' ] ( ( value , isRejected ) => {
277
+ start ( ) ;
278
+ } ) . weight ( 0 )
279
+ . then ( resolveGenerator )
280
+ [ catchErrors ? 'done' : 'finally' ] ( ( value , isRejected ) => {
266
281
started && current . pending -- ;
267
282
removeElement ( promises , promise ) ;
268
283
combine && argsToPromiseMap . delete ( promise ) ;
269
284
queue . length && queue . shift ( ) ( ) ;
270
-
271
285
const canceled = ! ! ( isRejected && CanceledError . isCanceledError ( value ) ) ;
272
286
273
- if ( canceled && value . code === E_REASON_UNMOUNTED ) {
287
+ if ( canceled && ( value . code === E_REASON_UNMOUNTED || value . code === E_REASON_RESTART ) ) {
274
288
return ;
275
289
}
276
290
277
- state && singleThreaded && setState ( {
278
- done : true ,
291
+ states && singleThreaded && setDeepState ( {
279
292
pending : false ,
293
+ done : true ,
280
294
error : isRejected ? value : undefined ,
281
295
result : isRejected ? undefined : value ,
282
296
canceled
283
297
} ) ;
284
298
} ) . weight ( 0 ) . aggregate ( ) ;
285
299
286
- promises . push ( promise ) ;
300
+ promises . push ( promise ) ;
287
301
288
- combine && argsToPromiseMap . set ( promise , args ) ;
302
+ combine && argsToPromiseMap . set ( promise , args ) ;
289
303
290
- return promise ;
291
- }
304
+ return promise ;
305
+ }
292
306
293
- const promise = resolveGenerator ( ) [ catchErrors ? 'done' : 'finally' ] ( ( ) => {
294
- removeElement ( promises , promise ) ;
295
- combine && argsToPromiseMap . delete ( promise ) ;
296
- } ) . weight ( 0 ) . aggregate ( ) ;
307
+ const promise = resolveGenerator ( ) [ catchErrors ? 'done' : 'finally' ] ( ( ) => {
308
+ removeElement ( promises , promise ) ;
309
+ combine && argsToPromiseMap . delete ( promise ) ;
310
+ } ) . weight ( 0 ) . aggregate ( ) ;
297
311
298
- promises . push ( promise ) ;
312
+ promises . push ( promise ) ;
313
+
314
+ if ( combine ) {
315
+ argsToPromiseMap . set ( promise , args ) ;
316
+ }
299
317
300
- if ( combine ) {
301
- argsToPromiseMap . set ( promise , args ) ;
318
+ return promise ;
302
319
}
303
320
304
- return promise ;
305
- } ) ;
321
+ fn . cancel = cancel ;
306
322
307
- const cancel = ( reason ) => {
308
- const _reason = isEvent ( reason ) ? undefined : reason ;
309
- current . promises . forEach ( promise => promise . cancel ( _reason ) ) ;
310
- current . promises . length = 0 ;
311
- } ;
323
+ return fn ;
324
+ } , deps ) ;
325
+
326
+ useEffect ( ( ) => {
327
+ return ( ) => callback . cancel ( E_REASON_UNMOUNTED ) ;
328
+ } , deps ) ;
312
329
313
330
if ( states ) {
314
331
if ( ! singleThreaded ) {
@@ -321,20 +338,14 @@ const useAsyncCallback = (generator, options) => {
321
338
callback . canceled = state . canceled ;
322
339
323
340
callback [ Symbol . iterator ] = function * ( ) {
324
- yield * [ callback , cancel , state . pending , state . done , state . result , state . error , state . canceled ] ;
341
+ yield * [ callback , callback . cancel , state . pending , state . done , state . result , state . error , state . canceled ] ;
325
342
}
326
343
} else {
327
344
callback [ Symbol . iterator ] = function * ( ) {
328
- yield * [ callback , cancel ] ;
345
+ yield * [ callback , callback . cancel ] ;
329
346
}
330
347
}
331
348
332
- useEffect ( ( ) => {
333
- return ( ) => cancel ( E_REASON_UNMOUNTED ) ;
334
- } , deps ) ;
335
-
336
- callback . cancel = cancel ;
337
-
338
349
return callback ;
339
350
}
340
351
0 commit comments