바닐라 비동기 디바운스 가이드
비동기 디바운스는 디바운스 가이드에서 설명한 타이밍 동작을 유지하면서 Promise 결과, 재시도, 오류 콜백, 진행 중인 작업 제어 기능을 추가합니다.
디바운스 작업이 필요한 값을 반환하거나 거부될 수 있거나 재시도 및 중단 지원이 필요할 때 비동기 디바운스를 사용합니다. 동기 Debouncer는 부수 효과로 비동기 함수를 호출할 수 있지만 그 결과로 생성되는 Promise는 관리하지 않습니다.
빠른 시작
호출 가능한 함수만 필요하다면 asyncDebounce를 사용합니다.
import { asyncDebounce } from '@tanstack/pacer'
const search = asyncDebounce(
async (query: string) => {
const response = await fetch(`/api/search?q=${encodeURIComponent(query)}`)
if (!response.ok) throw new Error('Search failed')
return response.json()
},
{ wait: 300 },
)
const results = await search('pacer')
메서드, 상태 또는 콜백이 필요하다면 AsyncDebouncer를 사용합니다.
import { AsyncDebouncer } from '@tanstack/pacer'
const search = new AsyncDebouncer(fetchSearchResults, {
wait: 300,
onSuccess: (results, args) => {
console.log('Results for:', args[0], results)
},
onError: (error, args) => {
console.error('Search failed for:', args[0], error)
},
})
const results = await search.maybeExecute('pacer')
타이밍 옵션의 기본값은 동기 디바운스와 동일한 leading: false 및 trailing: true입니다. 호출할 때마다 후행 지연이 재설정되며 지연이 끝날 때 가장 최근 인수를 사용합니다.
Promise 결과
maybeExecute()는 Promise를 반환합니다. 실행을 소유한 호출은 해당 실행 결과로 이행됩니다. 대기 중인 후행 호출이 교체될 때는 다음과 같은 중요한 결과가 발생합니다.
call A ──────┐
├─ call B replaces A ───── wait ───── execute B
Promise A ───┘ resolves with the previous lastResult
Promise B ─────────────────────────────── resolves with result B
교체된 호출은 디바운서의 현재 lastResult로 즉시 이행되며, 첫 성공 실행 전에는 대개 undefined입니다. 더 새로운 호출을 기다리지 않습니다. 가장 최근 호출이 반환한 Promise를 대기 중인 결과의 소유자로 취급합니다.
모든 호출을 실행하고 각각의 결과를 생성해야 한다면 대신 비동기 큐를 사용합니다.
선행 및 후행 실행
네 가지 조합은 동기 디바운스와 동일합니다.
leading | trailing | 동작 |
|---|---|---|
false | true | 호출이 wait밀리초 동안 멈춘 후 실행합니다. 기본값입니다. |
true | false | 즉시 실행한 다음 유휴 기간이 끝날 때까지 호출을 무시합니다. |
true | true | 첫 호출은 즉시 실행하고 이후의 가장 최근 호출은 후행 에지에서 실행합니다. |
false | false | 함수를 실행하지 않고 호출을 기록합니다. |
두 에지를 모두 활성화하면 단일 호출은 선행 에지에서만 실행됩니다. 후행 실행이 일어나려면 대기 기간 중에 다른 호출이 있어야 합니다.
오류 및 콜백
비동기 디바운서는 각 실제 실행 전후에 다음 콜백을 제공합니다.
onSuccess(result, args, debouncer)는 실행이 성공한 후 실행됩니다.onError(error, args, debouncer)는 실행의 재시도가 실패한 후 실행됩니다.onSettled(args, debouncer)는 어느 결과든 완료된 후 실행됩니다.
onError가 없으면 throwOnError의 기본값이 true이므로 실행 실패 시 Promise가 거부됩니다. onError를 제공하면 이 기본값이 false로 바뀌고 Promise는 현재 lastResult로 이행됩니다. 다른 동작이 필요하다면 throwOnError를 명시적으로 설정합니다.
콜백은 실행마다 동작하며 maybeExecute()의 모든 호출마다 동작하지는 않습니다. 교체되거나 취소된 대기 호출은 래핑된 함수에 절대 도달하지 않습니다.
실패한 실행 재시도
실행이 시작된 후 재시도하려면 asyncRetryerOptions를 전달합니다.
const save = new AsyncDebouncer(saveDraft, {
wait: 500,
asyncRetryerOptions: {
maxAttempts: 3,
backoff: 'exponential',
baseWait: 500,
jitter: 0.2,
},
})
maxAttempts에는 첫 시도가 포함됩니다. 디바운스가 하나의 논리적 실행이 시작되는 시점을 결정하면 재시도기가 해당 실행의 시도를 관리합니다. 재시도 안전성, 백오프, 시간 제한 동작은 비동기 재시도 가이드를 참고합니다.
대기 중인 작업 취소 및 활성 작업 중단
대기 중인 작업과 활성 작업은 별도로 제어합니다.
cancel()은 아직 시작하지 않은 후행 실행을 제거합니다. 활성 Promise는 중지하지 않습니다.abort()는 활성 실행을 중단합니다. 대기 중인 후행 실행은 제거하지 않습니다.flush()는 대기 중인 작업을 즉시 시작하고 결과를 반환합니다. 활성 작업에는 영향을 주지 않습니다.
fetch 같은 기반 작업을 중지하려면 디바운서의 신호를 전달합니다.
const search = new AsyncDebouncer(
async (query: string) => {
const response = await fetch(`/api/search?q=${query}`, {
signal: search.getAbortSignal() ?? undefined,
})
return response.json()
},
{ wait: 300 },
)
search.maybeExecute('pacer')
search.abort()
신호를 사용하지 않고 abort()를 호출하면 재시도 관리는 중지되지만 임의의 Promise를 강제로 중지할 수는 없습니다.
안전하게 재설정하기
reset()은 기본 상태를 복원하지만 예약된 후행 시간 제한을 제거하지 않으며 활성 작업의 중지를 보장하지도 않습니다. 완전히 정리해야 한다면 먼저 생명주기 메서드를 사용합니다.
search.cancel()
search.abort()
search.reset()
설정
wait와 enabled에는 값 또는 디바운서 인스턴스를 받는 함수를 지정할 수 있습니다. setOptions()는 새 옵션을 현재 설정에 병합합니다.
search.setOptions({
enabled: (debouncer) => debouncer.store.state.errorCount < 3,
wait: (debouncer) =>
debouncer.store.state.successCount === 0 ? 200 : 500,
})
wait를 변경해도 기존 시간 제한의 일정은 다시 잡히지 않습니다. 새 값은 이후 작업을 예약할 때 적용됩니다.
재사용할 수 있고 타입 검사를 거친 옵션 객체를 정의하려면 asyncDebouncerOptions()를 사용합니다.
상태
클래스는 debouncer.store에 상태를 저장합니다.
애플리케이션이 유지한 일부 상태를 복원하려면 부분 스냅샷을 initialState로 전달합니다. 이 스냅샷은 기본값과 병합됩니다. 지속 가능한 필드만 복원합니다. 대기 중인 타이머와 활성 실행은 복원되지 않습니다.
일반적으로 유용한 속성은 다음과 같습니다.
isPending: 후행 실행이 예약되어 있는지 나타냅니다.isExecuting: 래핑된 함수가 활성 상태인지 나타냅니다.lastArgs: 대기 중인 작업을 위해 유지한 인수입니다.lastResult: 가장 최근의 성공 결과입니다.successCount,errorCount,settleCount: 실행 결과 횟수입니다.status:'disabled','idle','pending','executing'또는'settled'입니다.
전체 상태와 옵션 타입은 AsyncDebouncer API 레퍼런스를 참고합니다.