Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/humble-coats-shop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tanstack/pacer': patch
---

Fixed a bug in AsyncDebouncer where getAbortSignal() incorrectly returned null due to an internal execution ID mismatch. Abort signals can now be properly attached to underlying async tasks.
2 changes: 1 addition & 1 deletion packages/pacer/src/async-debouncer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ export class AsyncDebouncer<TFn extends AnyAsyncFunction> {
...args: Parameters<TFn>
): Promise<ReturnType<TFn> | undefined> => {
if (!this.#getEnabled()) return undefined
const currentMaybeExecuteCount = this.store.state.maybeExecuteCount + 1
const currentMaybeExecuteCount = this.store.state.maybeExecuteCount

try {
this.#setState({ isExecuting: true })
Expand Down
24 changes: 23 additions & 1 deletion packages/pacer/tests/async-debouncer.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { afterEach, beforeEach, describe, expect, it, vi, } from 'vitest'
import { AsyncDebouncer, asyncDebounce } from '../src/async-debouncer'

describe('AsyncDebouncer', () => {
Expand Down Expand Up @@ -1358,5 +1358,27 @@ describe('asyncDebounce helper function', () => {
expect(typeof debouncer.getAbortSignal).toBe('function')
expect(debouncer.getAbortSignal()).toBeNull()
})


it('should return an AbortSignal and mark it aborted when abort() is called', async () => {
const debouncer = new AsyncDebouncer(
async () => {
const signal = debouncer.getAbortSignal()
expect(signal).toBeInstanceOf(AbortSignal)
expect(signal?.aborted).toBe(false)
return 'result'
},
{ wait: 300 },
)


debouncer.maybeExecute()
vi.advanceTimersByTime(150)
const promise = debouncer.maybeExecute()
vi.advanceTimersByTime(300)
debouncer.abort()
expect(debouncer.getAbortSignal()?.aborted ?? true).toBe(true)
await promise
})
})
})