본문으로 건너뛰기

Angular 배칭 가이드

배칭은 항목을 수집해 하나의 함수에 배열로 전달합니다. 배치가 설정된 크기에 도달하거나 설정된 대기 시간 동안 새 항목이 추가되지 않을 때, 또는 사용자 정의 로직에서 준비되었다고 판단할 때 배치를 실행할 수 있습니다.

배칭은 여러 항목을 함께 처리하여 작업 수를 줄입니다. 큐와 달리 각 항목마다 래핑된 함수를 한 번씩 호출하지 않습니다.

배칭의 작동 방식​

Batching (process every 3 items or after 2 quiet ticks)
Timeline: [1 second per tick]
Calls: ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️
Batch: [ABC] [] [DE] [] [FGH] []
Executed: ✅ ✅ ✅
[======================================================]
^ Items are grouped and processed together

[Size reached] [Wait elapsed] [Size reached]

각 실행에는 현재 수집된 항목의 복사본이 전달됩니다. 배처는 래핑된 함수를 호출하기 전에 해당 항목을 비웁니다.

배칭을 사용해야 하는 경우​

다음과 같은 경우 배칭을 선택합니다.

  • 일괄 작업이 개별 작업보다 효율적인 경우
  • 네트워크 요청, 데이터베이스 쓰기, 분석 이벤트를 그룹화할 수 있는 경우
  • 최대 배치 크기나 유휴 시간 트리거가 워크로드에 적합한 경우
  • 개별 항목의 결과가 필요하지 않은 경우

다음과 같은 경우 다른 유틸리티를 선택합니다.

  • 모든 항목을 개별적으로 순서대로 실행해야 하는 경우 큐을 사용합니다.
  • 가장 최근 값만 중요한 경우 디바운스을 사용합니다.
  • 호출 간에 시간 간격을 두어야 하는 경우 스로틀을 사용합니다.
  • 배치 처리가 Promise를 반환하거나 재시도 및 중단 지원이 필요한 경우 비동기 배칭을 사용합니다.

API 선택하기​

  • 항목 추가 함수에는 injectBatchedCallback을 사용합니다.
  • 플러시, 취소, 수집된 항목, 선택된 상태가 필요하면 injectBatcher를 사용합니다.

컴포넌트에서 항목 추가만 필요하다면 콜백 API를 사용합니다. flush(), cancel(), 수집된 항목, 선택한 상태, 동적 옵션이 필요하면 인스턴스 API를 사용합니다.

Angular 예시​

import { injectBatchedCallback, injectBatcher } from '@tanstack/angular-pacer'

export class AnalyticsComponent {
readonly addEvent = injectBatchedCallback(sendEvents, {
maxSize: 20,
wait: 1000,
})
readonly batcher = injectBatcher(
sendEvents,
{ maxSize: 20, wait: 1000 },
(state) => ({
size: state.size,
}),
)
}

이 가이드의 이후 핵심 코드 조각은 injectBatcher을 사용하며 Angular 주입 컨텍스트 안에서 실행된다고 가정합니다.

배치 트리거 선택하기​

배치 크기​

maxSize는 수집된 항목 수가 제한에 도달하는 즉시 배치를 실행합니다.

const batcher = injectBatcher(processBatch, {
maxSize: 100,
})

기본값은 Infinity이므로 크기 트리거를 제공하지 않으면 비활성화됩니다.

대기 시간​

wait는 설정된 시간 동안 새 항목이 추가되지 않으면 배치를 실행합니다. 항목을 추가할 때마다 타이머가 다시 시작합니다.

const batcher = injectBatcher(processBatch, {
wait: 1000,
})

기본값은 Infinity이므로 시간 트리거를 제공하지 않으면 비활성화됩니다. 항목이 계속 들어오면 타이머도 계속 다시 시작할 수 있습니다. 지속적인 트래픽에서도 배치를 결국 실행해야 한다면 wait와 maxSize를 함께 사용합니다.

사용자 정의 트리거​

getShouldExecute는 각 항목을 추가한 후 실행됩니다. 현재 배치를 즉시 실행하려면 true를 반환합니다.

const batcher = injectBatcher<number>(processBatch, {
getShouldExecute: (items) => items.includes(0),
})

batcher.addItem(4)
batcher.addItem(0) // Executes [4, 0].

여러 트리거를 설정한 경우 가장 먼저 조건에 도달한 트리거가 배치를 실행합니다.

수집된 항목 제어하기​

플러시​

flush()는 대기 중인 타이머를 지우고 현재 수집된 모든 항목을 실행합니다. 배치가 비어 있으면 아무 동작도 하지 않습니다.

batcher.addItem('event-1')
batcher.addItem('event-2')
batcher.flush()

취소​

cancel()은 대기 중인 타이머를 지우지만 수집된 항목은 유지합니다. 이후 항목이 새 타이머를 예약하거나 flush()를 호출할 수 있습니다.

batcher.cancel()
console.log(batcher.peekAllItems()) // Items are still present.

비우기​

clear()는 수집된 모든 항목을 제거합니다. 타이머 자체는 지우지 않지만 항목을 더 추가하지 않으면 해당 타이머에서 실행할 항목이 없습니다.

batcher.clear()

재설정​

reset()은 배치 상태와 카운터를 기본값으로 복원합니다. 이미 예약된 타이머는 취소하지 않습니다. 대기 작업을 버려야 한다면 cancel()을 호출한 다음 reset()을 호출합니다.

batcher.cancel()
batcher.reset()

배치 설정 및 관찰하기​

향후 트리거 동작을 업데이트하려면 setOptions()를 사용합니다.

batcher.setOptions({
maxSize: 20,
wait: 500,
})

wait를 변경해도 기존 타이머를 다시 예약하지 않습니다. 다음 addItem() 호출이 현재 값을 사용해 해당 타이머를 대체합니다.

wait 옵션에는 배처 인스턴스를 받는 함수를 사용할 수 있습니다.

const batcher = injectBatcher(processBatch, {
wait: (batcher) => (batcher.store.state.size > 10 ? 100 : 500),
})

컬렉션 변경을 관찰하려면 onItemsChange를, 완료된 배치 호출을 관찰하려면 onExecute를 사용합니다.

const batcher = injectBatcher(processBatch, {
maxSize: 10,
onItemsChange: (batcher) => {
console.log('Collected:', batcher.store.state.size)
},
onExecute: (items, batcher) => {
console.log('Processed:', items)
console.log('Batches:', batcher.store.state.executionCount)
},
})

배처를 일시 중지하는 데 started를 사용하지 않습니다. 현재 아무 동작도 하지 않으므로 모든 addItem() 호출에서 설정된 트리거를 평가합니다.

Angular 수명 주기​

어댑터는 소유자가 제거될 때 수집된 항목은 유지하면서 대기 중인 타이머를 취소합니다. onUnmount를 제공하면 이 기본 정리 동작을 대체하므로 사용자 정의 콜백에서 필요한 모든 수명 주기 작업을 수행해야 합니다. 사용자 정의 정리 과정에서 작업을 플러시하면 컴포넌트가 제거되는 동안 사용자 콜백이 실행될 수 있다는 점에 유의해야 합니다.

반응형 상태​

어댑터는 셀렉터 인수가 반환한 상태만 구독합니다. 셀렉터가 없으면 어댑터 상태는 비어 있습니다. 일반적으로 컴포넌트나 서비스의 필드 초기화 구문과 같은 Angular 주입 컨텍스트에서 유틸리티를 생성하고 뷰에서 사용하는 필드만 선택합니다.

const batcher = injectBatcher(
processBatch,
{ maxSize: 20, wait: 1000 },
(state) => ({
size: state.size,
isPending: state.isPending,
}),
)

console.log(batcher.state().size, batcher.state().isPending)

옵션 함수와 수명 주기 콜백은 기반 공개 유틸리티 인스턴스를 받습니다. 위 예제처럼 해당 콜백 안에서 .store.state를 읽는 방식을 지원합니다. 렌더링 코드는 여기에 나온 선택된 어댑터 상태를 읽어야 합니다.

앱에서 유지한 선택 상태를 복원하려면 initialState로 부분 스냅샷을 전달합니다. 이 스냅샷은 기본값과 병합됩니다. 지속 가능한 필드만 복원합니다. 대기 중인 타이머는 복원되지 않습니다.

일반적으로 유용한 상태에는 다음 항목이 포함됩니다.

  • items: 현재 수집된 항목입니다.
  • size: 수집된 항목 수입니다.
  • isEmpty: 배치가 비어 있는지 여부입니다.
  • isPending: 대기 타이머가 활성 상태인지 여부입니다.
  • executionCount: 완료된 배치 실행 횟수입니다.
  • totalItemsProcessed: 완료된 배치 실행에 전달된 항목 수입니다.
  • status: 'idle' 또는 'pending'입니다.

어댑터 시그니처는 Angular API 레퍼런스를, 전체 옵션과 상태 타입은 공개 핵심 레퍼런스를 참고합니다.