Skip to content

Commit 13ce153

Browse files
authored
feat: add back off algorithm to errorRetryInterval (#19)
reference: #18
1 parent c74a768 commit 13ce153

File tree

2 files changed

+56
-6
lines changed

2 files changed

+56
-6
lines changed

src/__tests__/index.test.tsx

+36
Original file line numberDiff line numberDiff line change
@@ -1463,6 +1463,42 @@ describe('useRequest', () => {
14631463
expect(wrapper.text()).toBe('false');
14641464
});
14651465

1466+
test('errorRetry should work. case 3', async () => {
1467+
const mockFn = jest.fn();
1468+
1469+
const wrapper = shallowMount(
1470+
defineComponent({
1471+
setup() {
1472+
const { run, loading } = useRequest(failedRequest, {
1473+
manual: true,
1474+
errorRetryCount: 10,
1475+
onError: () => mockFn(),
1476+
});
1477+
const handleClick = () => run();
1478+
return () => (
1479+
<button onClick={handleClick}>{`${loading.value}`}</button>
1480+
);
1481+
},
1482+
}),
1483+
);
1484+
1485+
await wrapper.find('button').trigger('click');
1486+
expect(wrapper.text()).toBe('true');
1487+
await waitForTime(1000);
1488+
expect(wrapper.text()).toBe('false');
1489+
1490+
// retrying
1491+
for (let index = 0; index < 10; index++) {
1492+
await waitForAll();
1493+
expect(wrapper.text()).toBe('false');
1494+
}
1495+
1496+
// stop retry
1497+
await waitForAll();
1498+
expect(wrapper.text()).toBe('false');
1499+
expect(mockFn).toHaveBeenCalledTimes(11);
1500+
});
1501+
14661502
test('errorRetry should work with pollingInterval', async () => {
14671503
let flag = true;
14681504
const mixinRequest = () => {

src/core/createQuery.ts

+20-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import debounce from 'lodash/debounce';
22
import throttle from 'lodash/throttle';
3-
import { nextTick, Ref, ref } from 'vue';
3+
import { computed, nextTick, Ref, ref } from 'vue';
44
import { Config } from './config';
55
import { Queries } from './useAsyncQuery';
66
import {
@@ -78,7 +78,7 @@ const createQuery = <R, P extends unknown[]>(
7878
onError,
7979
} = config;
8080

81-
let retriedCount = 0;
81+
const retriedCount = ref(0);
8282
const loading = ref(initialState?.loading ?? false);
8383
const data = ref(initialState?.data ?? initialData) as Ref<R>;
8484
const error = ref(initialState?.error);
@@ -96,7 +96,7 @@ const createQuery = <R, P extends unknown[]>(
9696

9797
// reset retried count
9898
const resetRetriedCount = () => {
99-
retriedCount = 0;
99+
retriedCount.value = 0;
100100
};
101101

102102
const count = ref(0);
@@ -154,15 +154,29 @@ const createQuery = <R, P extends unknown[]>(
154154
return () => timerId && clearTimeout(timerId);
155155
};
156156

157+
const actualErrorRetryInterval = computed(() => {
158+
if (errorRetryInterval) return errorRetryInterval;
159+
const baseTime = 1000;
160+
const minCoefficient = 1;
161+
const maxCoefficient = 9;
162+
// When retrying for the first time, in order to avoid the coefficient being 0
163+
// so replace 0 with 2, the coefficient range will become 1 - 2
164+
const coefficient = Math.floor(
165+
Math.random() * 2 ** Math.min(retriedCount.value, maxCoefficient) +
166+
minCoefficient,
167+
);
168+
return baseTime * coefficient;
169+
});
170+
157171
const errorRetryHooks = (retryFunc: () => void) => {
158172
let timerId: number;
159173
const isInfiniteRetry = errorRetryCount === -1;
160-
const hasRetryCount = retriedCount < errorRetryCount;
174+
const hasRetryCount = retriedCount.value < errorRetryCount;
161175

162176
// if errorRetryCount is -1, it will retry the request until it success
163177
if (error.value && (isInfiniteRetry || hasRetryCount)) {
164-
if (!isInfiniteRetry) retriedCount += 1;
165-
timerId = setTimeout(retryFunc, errorRetryInterval);
178+
if (!isInfiniteRetry) retriedCount.value += 1;
179+
timerId = setTimeout(retryFunc, actualErrorRetryInterval.value);
166180
}
167181
return () => timerId && clearTimeout(timerId);
168182
};

0 commit comments

Comments
 (0)