Skip to content

Commit 64c533f

Browse files
authored
feat(useTimtoutFn,useTimeoutPoll): align behavior (#4543)
1 parent 45e5cdd commit 64c533f

File tree

4 files changed

+90
-60
lines changed

4 files changed

+90
-60
lines changed
Lines changed: 46 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,52 @@
1-
import { describe, expect, it, vi } from 'vitest'
2-
import { effectScope, nextTick, ref } from 'vue'
1+
import { beforeEach, describe, expect, it, vi } from 'vitest'
2+
import { effectScope, ref } from 'vue'
33
import { useTimeoutPoll } from '.'
44

55
describe('useTimeoutPoll', () => {
6-
vi.useFakeTimers()
7-
function createTests(immediate: boolean) {
8-
it(`supports reactive intervals when immediate is ${immediate}`, async () => {
9-
const callback = vi.fn()
10-
const interval = ref(0)
11-
const { pause, resume } = useTimeoutPoll(callback, interval, { immediate })
12-
13-
if (!immediate)
14-
resume()
15-
expect(callback).toBeCalled()
16-
pause()
17-
18-
interval.value = 10
19-
20-
resume()
21-
callback.mockReset()
22-
expect(callback).not.toBeCalled()
23-
await vi.advanceTimersByTimeAsync(11)
24-
expect(callback).toBeCalled()
25-
26-
callback.mockReset()
27-
pause()
28-
await vi.advanceTimersByTimeAsync(11)
29-
expect(callback).not.toBeCalled()
30-
31-
resume()
32-
expect(callback).toBeCalled()
33-
34-
callback.mockReset()
35-
await vi.advanceTimersByTimeAsync(11)
6+
beforeEach(() => {
7+
vi.useFakeTimers()
8+
})
9+
10+
it('basic pause/resume', async () => {
11+
const callback = vi.fn()
12+
const interval = ref(0)
13+
const { pause, resume } = useTimeoutPoll(callback, interval)
14+
15+
await vi.advanceTimersByTimeAsync(1)
16+
expect(callback).toBeCalled()
17+
pause()
18+
interval.value = 10
19+
20+
resume()
21+
callback.mockReset()
22+
vi.advanceTimersByTime(1)
23+
expect(callback).not.toBeCalled()
24+
vi.advanceTimersByTime(10)
25+
expect(callback).toBeCalled()
26+
})
27+
28+
it('pause/resume with immediateCallback', async () => {
29+
const callback = vi.fn()
30+
useTimeoutPoll(callback, 50, { immediateCallback: true })
31+
32+
expect(callback).toHaveBeenCalledTimes(1)
33+
34+
vi.advanceTimersByTime(100)
35+
expect(callback).toHaveBeenCalledTimes(2)
36+
})
37+
38+
it('pause/resume in scope', async () => {
39+
const callback = vi.fn()
40+
const interval = ref(0)
41+
const scope = effectScope()
42+
await scope.run(async () => {
43+
useTimeoutPoll(callback, interval)
44+
vi.advanceTimersByTime(1)
3645
expect(callback).toBeCalled()
3746
})
38-
39-
it(`should pause when scope dispose and immediate is ${immediate}`, async () => {
40-
const callback = vi.fn()
41-
const interval = ref(0)
42-
const scope = effectScope()
43-
await scope.run(async () => {
44-
const { resume } = useTimeoutPoll(callback, interval, { immediate })
45-
46-
if (!immediate)
47-
resume()
48-
await nextTick()
49-
expect(callback).toBeCalled()
50-
})
51-
callback.mockReset()
52-
scope.stop()
53-
interval.value = 10
54-
await vi.advanceTimersByTimeAsync(11)
55-
expect(callback).not.toBeCalled()
56-
})
57-
}
58-
59-
createTests(true)
60-
createTests(false)
47+
callback.mockClear()
48+
await scope.stop()
49+
vi.advanceTimersByTime(60)
50+
expect(callback).toHaveBeenCalledTimes(0)
51+
})
6152
})

packages/core/useTimeoutPoll/index.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,33 @@ import type { Awaitable, MaybeRefOrGetter, Pausable, UseTimeoutFnOptions } from
22
import { isClient, tryOnScopeDispose, useTimeoutFn } from '@vueuse/shared'
33
import { ref } from 'vue'
44

5+
export interface UseTimeoutPollOptions {
6+
/**
7+
* Start the timer immediately
8+
*
9+
* @default true
10+
*/
11+
immediate?: boolean
12+
13+
/**
14+
* Execute the callback immediately after calling `resume`
15+
*
16+
* @default false
17+
*/
18+
immediateCallback?: boolean
19+
}
20+
521
export function useTimeoutPoll(
622
fn: () => Awaitable<void>,
723
interval: MaybeRefOrGetter<number>,
824
options: UseTimeoutFnOptions = {},
925
): Pausable {
1026
const {
1127
immediate = true,
28+
immediateCallback = false,
1229
} = options
1330

14-
const { start } = useTimeoutFn(loop, interval, { immediate: false })
31+
const { start } = useTimeoutFn(loop, interval, { immediate })
1532

1633
const isActive = ref(false)
1734

@@ -26,7 +43,9 @@ export function useTimeoutPoll(
2643
function resume() {
2744
if (!isActive.value) {
2845
isActive.value = true
29-
loop()
46+
if (immediateCallback)
47+
fn()
48+
start()
3049
}
3150
}
3251

packages/shared/useTimeoutFn/index.test.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ describe('useTimeoutFn', () => {
66
beforeEach(() => {
77
vi.useFakeTimers()
88
})
9-
it('supports reactive intervals', async () => {
9+
10+
it('basic start/stop', async () => {
1011
const callback = vi.fn()
1112
const interval = ref(0)
1213
const { start } = useTimeoutFn(callback, interval)
1314

14-
start()
1515
vi.advanceTimersByTime(1)
1616
expect(callback).toBeCalled()
1717

@@ -25,6 +25,16 @@ describe('useTimeoutFn', () => {
2525
expect(callback).toBeCalled()
2626
})
2727

28+
it('stop/start with immediateCallback', async () => {
29+
const callback = vi.fn()
30+
useTimeoutFn(callback, 50, { immediateCallback: true })
31+
32+
expect(callback).toHaveBeenCalledTimes(1)
33+
34+
vi.advanceTimersByTime(100)
35+
expect(callback).toHaveBeenCalledTimes(2)
36+
})
37+
2838
it('supports getting pending status', async () => {
2939
const callback = vi.fn()
3040
const { start, isPending } = useTimeoutFn(callback, 0, { immediate: false })

packages/shared/useTimeoutFn/index.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,18 @@ import { isClient } from '../utils'
55

66
export interface UseTimeoutFnOptions {
77
/**
8-
* Start the timer immediate after calling this function
8+
* Start the timer immediately
99
*
1010
* @default true
1111
*/
1212
immediate?: boolean
13+
14+
/**
15+
* Execute the callback immediately after calling `start`
16+
*
17+
* @default false
18+
*/
19+
immediateCallback?: boolean
1320
}
1421

1522
/**
@@ -26,6 +33,7 @@ export function useTimeoutFn<CallbackFn extends AnyFn>(
2633
): Stoppable<Parameters<CallbackFn> | []> {
2734
const {
2835
immediate = true,
36+
immediateCallback = false,
2937
} = options
3038

3139
const isPending = ref(false)
@@ -45,6 +53,8 @@ export function useTimeoutFn<CallbackFn extends AnyFn>(
4553
}
4654

4755
function start(...args: Parameters<CallbackFn> | []) {
56+
if (immediateCallback)
57+
cb()
4858
clear()
4959
isPending.value = true
5060
timer = setTimeout(() => {

0 commit comments

Comments
 (0)