| 73 | } |
| 74 | |
| 75 | export function createRetryer<TData = unknown, TError = DefaultError>( |
| 76 | config: RetryerConfig<TData, TError>, |
| 77 | ): Retryer<TData> { |
| 78 | let isRetryCancelled = false |
| 79 | let failureCount = 0 |
| 80 | let continueFn: ((value?: unknown) => void) | undefined |
| 81 | |
| 82 | const thenable = pendingThenable<TData>() |
| 83 | |
| 84 | const isResolved = () => |
| 85 | (thenable.status as Thenable<TData>['status']) !== 'pending' |
| 86 | |
| 87 | const cancel = (cancelOptions?: CancelOptions): void => { |
| 88 | if (!isResolved()) { |
| 89 | const error = new CancelledError(cancelOptions) as TError |
| 90 | reject(error) |
| 91 | |
| 92 | config.onCancel?.(error) |
| 93 | } |
| 94 | } |
| 95 | const cancelRetry = () => { |
| 96 | isRetryCancelled = true |
| 97 | } |
| 98 | |
| 99 | const continueRetry = () => { |
| 100 | isRetryCancelled = false |
| 101 | } |
| 102 | |
| 103 | const canContinue = () => |
| 104 | focusManager.isFocused() && |
| 105 | (config.networkMode === 'always' || onlineManager.isOnline()) && |
| 106 | config.canRun() |
| 107 | |
| 108 | const canStart = () => canFetch(config.networkMode) && config.canRun() |
| 109 | |
| 110 | const resolve = (value: any) => { |
| 111 | if (!isResolved()) { |
| 112 | continueFn?.() |
| 113 | thenable.resolve(value) |
| 114 | } |
| 115 | } |
| 116 | |
| 117 | const reject = (value: any) => { |
| 118 | if (!isResolved()) { |
| 119 | continueFn?.() |
| 120 | thenable.reject(value) |
| 121 | } |
| 122 | } |
| 123 | |
| 124 | const pause = () => { |
| 125 | return new Promise((continueResolve) => { |
| 126 | continueFn = (value) => { |
| 127 | if (isResolved() || canContinue()) { |
| 128 | continueResolve(value) |
| 129 | } |
| 130 | } |
| 131 | config.onPause?.() |
| 132 | }).then(() => { |