debounce

마지막 호출 이후 wait만큼 지날 때까지 함수 호출을 미룹니다 — 연속된 호출 중 마지막 하나만 살아남습니다.

Debounced<T> debounce<T>(void Function(T arg) func, Duration wait, {bool leading = false}) class Debounced<T> { void call(T arg); // Debounced is callable: debounced(arg) void cancel(); } FxEvents<T> FxEvents<T>.debounce(Duration window) // chain (events) Debounced<T> (void Function(T arg)).fxDebounce(Duration wait, {bool leading = false}) // method

강의

debounce는 콜백을 감싸서, 짧은 시간에 몰린 반복 호출을 하나의 호출로 합쳐 줍니다. 호출이 있을 때마다 wait 길이의 타이머가 다시 시작되고, 감싼 func는 다른 호출 없이 wait온전히 지났을 때 비로소 실행됩니다 — 그리고 마지막 호출에 전달된 인자로 실행됩니다. "사용자가 타이핑을 멈춘 뒤에 검색한다"는 전형적인 패턴이 바로 이것입니다.

JS에서 FxTS는 반환된 함수에 .cancel() 메서드를 직접 붙입니다. Dart 함수는 추가 멤버를 가질 수 없기 때문에, FxDart는 대신 Debounced<T>를 반환합니다 — call(T arg) 메서드를 가진 클래스이며, Dart의 call() 관례 덕분에 평범한 함수 호출 문법(debounced(arg))으로 호출할 수 있고, 대기 중인 실행을 버리는 .cancel()도 따로 제공합니다.

기본값(leading: false)에서는 트레일링 에지만 발화합니다 — 연속 호출이 끝나고 잠잠해진 뒤의 마지막 호출입니다. leading: true를 주면 대신 연속 호출 중 호출이 즉시 발화하고, 다음 잠잠해지는 구간이 올 때까지의 나머지 호출은 모두 억제됩니다.

데모 1 · 트레일링 에지(기본 동작)

빠르게 이어진 세 번의 호출이 하나로 합쳐지고, 마지막 인자만 남습니다.

데모 2 · 리딩 에지와 cancel()

leading: true는 즉시 발화한 뒤 나머지 연속 호출을 억제하고, .cancel()은 대기 중인 트레일링 호출을 통째로 버립니다.

메서드 표기

콜백 쪽에서 같은 것을 메서드로 부를 수 있습니다. saveDraft.fxDebounce(wait)debounce(saveDraft, wait)와 같고, 이름 붙은 인자도 그대로 받습니다.

void saveDraft(String text) => _post(text);

final save = saveDraft.fxDebounce(const Duration(milliseconds: 300));
save('h');
save('he');
save('hello');   // only this one reaches _post

fx 접두사는 의도한 것입니다. 어느 라이브러리가 콜백을 감싸는지 드러내고, 맨 이름은 프로젝트가 자기 함수 타입에 붙일 몫으로 남겨 둡니다 — fx의 getter 표기와 같은 규칙입니다.

직접 해 보기

연습: savedebounce로 감싸(wait는 100ms) 아래 연속 호출 중 마지막 값만 살아남게 만들어 보세요.

이벤트 스트림에서

같은 아이디어가 이벤트 레이어에도 있습니다. 몰아치는 대상이 콜백이 아니라 Stream이라면 fxEvents(s).debounce(window)가 각 버스트의 트레일링 값을 — window 동안 새 이벤트가 없을 때 — 내보내고, 스트림이 닫힐 때 아직 대기 중인 값은 버려지지 않고 마지막에 방출됩니다. 이 체인이 속한 곳은 fxEvents 문서를 참고하세요.

관련 항목: throttle — 잠잠해진 뒤가 아니라 일정 주기로 발화 · delay & sleep — 타이밍 데모를 만드는 재료 · concurrent — 비동기 파이프라인의 속도 제한 · shuffle — 시드를 지정하는 난수