주제선정
시간이 조금 지났지만 한때 앱의 오류가 발생했던 적이 있다.
분명 유저가 채팅방을 생성하면 한번만 생성되어야 되는데 짧은 시간에 여러번 터치하게 되면 여러개의 방이 생기는 문제가 발생했다.
물론 유저가 악의적으로 해당 사항을 지속했다면 문제가 됐을것이다.
특히 내 도메인이 금융쪽이였으면 엄청난 큰 문제가 발생했을 것이다.
항상 만들면서 기능만 개발하기에 급급했던 내 잘못이였다.
그래서 이걸 해결하고자 했을때 여러 방법이 있었다.
처음에 내가 생각했던 방법은 bool 값을 넣어서 try catch final 로 진입자체를 막는방법 이였지만
조금 검색하다보니 Debounce 와 Throttle 이라는 라이브러리가 존재하는것 알았고 해당 라이브러리를 사용해서 고쳤다.
그래서 이번에는 해당 개념에 대해서 조금 더 자세히 공부하고, 라이브러리를 사용하는 것과 직접 구현하는 방법, 원래 생각했던 try catch finally의 사용 예제를 공유하고 비교해보려고 한다.
이번에는 라이브러리는 해당 라이브러리를 사용해서 작성하려고 한다.
https://pub.dev/packages/easy_debounce
easy_debounce | Dart package
An extremely easy-to-use method call debouncer package for Dart/Flutter.
pub.dev
우선 해당 에러를 가정하기 위해 간단하게 Hello Flutter 를 받아오는 API 를 만들어서 간단하게 dio 를 통해서 get 방식으로 가져와서 사용했다. 별거 아니긴 하지만 이래서 풀스택이 좋은건가 싶다.
Debounce
Debounce 의 개념
Debounce는 반복적인 이벤트의 실행을 지정된 이후 시간이 지난 후 이벤트가 실행된다.
Debounce 시간을 400ms 로 지정했다고 가정해보자
맨 처음 버튼을 정상적으로 한번 눌렀을 경우 400ms 이후 함수가 호출된다
그러면 빠르게 버튼을 10번 눌렀다고 가정해보자 어떻게 될까?
첫 버튼이 입력되고 다음 버튼의 입력을 지켜보고있다가 다음 입력이 일어나면 다시 400ms가 초기화 되면서
입력이 일어나지 않는 400ms 가 되면 함수를 한번 실행시켜준다.
예를 들어서 인터넷 쇼핑을할때 장바구니에 물건을 넣는다고 가정해보자
그러면 유저가 어떤 물건을 몇개를 담았는지 서버에 전송해야된다.
근데 유저가 버튼을 누를때마다 서버로 통신을하고 DB에 반영된다고 하면 상당히 비효율적일것이다.
이런 문제를 해결하기위해 등장했다고 한다.
또다른 예시로 검색 기능을 호출한다고 가정해보자
유저가 글자를 하나하나 입력할때마다 API 를 호출하면 "제주" 이 단어를 검색하는동안 "ㅈ" 에서 한번 "제" 에서 한번 이런식으로 호출이 증가하게 된다. 이것 방지하기위해서 디바운스를 적용한다고 한다.
Debounce 는 주로 검색창 입력, 유저 타이핑, 상품 구매 버튼 등에서 사용된다고 한다.
Debounce가 적용된 원을 직접 움직일 수 있다
https://rxmarbles.com/#debounce
Debounce 사용 예제
사실 라이브러리 사용이라 별로 어려운건 없다
void _incrementDebounceCounter() {
EasyDebounce.debounce('debounce', const Duration(milliseconds: 400), () {
setState(() {
_debouncecounter++;
});
callAPI('debounce');
});
}
Throttle
Throttle 의 개념
Throttle은 이벤트가 연속적으로 발생하면 일정한 시간동안 일어나게 되고 그 사이에 발생하는 다른 이벤트들은 무시하게 된다.
여기서 Debounce 와 다른점은 Throttle은 연속된 이벤트가 발생하더라도 타이머를 초기화하지 않는 것이다
만약 임계 시간을 400ms로 설정하고 390ms 에 버튼을 누르면 Debounce 와 같은경우는 타이머가 다시 400ms로 초기화 되겠지만 Throttle 은 타이머가 초기화 되지않고 발생한 이벤트에 대해서 무시하게 된다.
예를들어 스크롤 이벤트에 400ms의 Throttle 을 적용했다고 가정해보자.
Throttle을 통해서 스크롤의 끝에 도달하면 한번만 호출하게 된다
만약 Debounce 가 해당 기능에 적용되었다고 가정해보자
한번만 이벤트를 수행하게되면 큰 문제는 없이 작동된다 하지만 여러번 스크롤 이벤트를 호출한다면? 계속 400ms 의 타이머가 초기화되어 결국 함수가 호출되지 않을것이다.
참 같으면서도 많이 다르다.
Throttle 이 적용된 원을 직접 움직일 수 있다.
https://rxmarbles.com/#throttle
Throttle 사용 예제
void _incrementThrottleCounter() {
EasyThrottle.throttle('throttle', const Duration(milliseconds: 400), () {
setState(() {
_throttlecounter++;
});
callAPI('throttle');
});
}
호출 결과 비교
확실히 결과를 놓고보니 비교가 편한것 같다.
눈에 잘 보이기 위해서 호출 관련 부분의 호출 횟수를 같이 넣어봤다
Debounce와 Throttle 직접 구현하기
Debounce와 Throttle을 찾아보다가 직접 구현하신 분도 봤다 해당 내용을 참고해서 작성해봤다
[flutter]throttle, debounce 만들기, 구현 예제 by Dart
다른 언어로 프론트 개발을 해봤다면 이미 사용해봤거나 개념 정도는 익히고 있겠지만 flutter 그리고 Dart가 첫 개발 언어이신 분들을 위해 간단히 요약하자면throttle ➡️ 지정된 시간동안 연속
velog.io
Debounce
class Debounce {
final Duration delay;
Timer? _timer;
Debounce({required this.delay});
run(action) {
// 이미 기다리고 있었다면 타이머를 초기화
if (_timer != null) {
_timer!.cancel();
}
// 지정된 시간이 지나면 action을 실행
_timer = Timer(delay, action);
}
}
Debounce debounce = Debounce(delay: const Duration(milliseconds: 400));
debounce.run(() {
callAPI('Handmade debounce');
});
Throttle
class Throttle {
final Duration delay;
bool waiting = false;
Timer? _timer;
Throttle({required this.delay});
void run(action) {
// 타이머를 기다리지 않을 때만
if (!waiting) {
// action을 실행하고 이벤트를 기다림
action();
waiting = true;
// 지정된 시간이 지나면 waiting을 풀어줌
_timer = Timer(delay, () {
waiting = false;
});
}
}
}
Throttle throttle = Throttle(delay: const Duration(milliseconds: 400));
debounce.run(() {
callAPI('Handmade debounce');
});
try catch finally 사용해보기
사실살 내 기준에서 제일 간편한 방법이다
bool 값 하나 넣어주고 try catch final 로 상태관리하기 이렇게하면 이전 이벤트가 종료 직전에는 api가 호출이 안되니까 말이다.
근데 지금 공부하면서 보니까 Debounce 나 Throttle 을 상황에 맞게 쓰는게 더 안전하게 보인다.
bool isDoing = false;
void _tryCatchFinally() async {
try {
if (isDoing) {
return;
}
isDoing = true;
await callAPI('try');
} catch (e) {
if (kDebugMode) {
print(e);
}
} finally {
isDoing = false;
}
}
코드
전체코드는 깃허브에서 확인할 수 있다.
https://github.com/Hsungjin/Flutter/tree/main/personal_study/debounce_throttle
Flutter/personal_study/debounce_throttle at main · Hsungjin/Flutter
Contribute to Hsungjin/Flutter development by creating an account on GitHub.
github.com
결론
동일하게 함수의 수행을 막는 방법이라고해도 참 여러가지 방법이 있는것 같다.
항상 개발을 하면서 느끼는게 최선의 선택은 없고 차선책을 강구해야되는것 같다.
그리고 해결 방법에 대해서 한번만 생각해보지 말고 꼭 여러번 생각하면서 검증의 시간도 필요 한 것 같다.
참조
[flutter]throttle, debounce 만들기, 구현 예제 by Dart
다른 언어로 프론트 개발을 해봤다면 이미 사용해봤거나 개념 정도는 익히고 있겠지만 flutter 그리고 Dart가 첫 개발 언어이신 분들을 위해 간단히 요약하자면throttle ➡️ 지정된 시간동안 연속
velog.io
https://medium.com/@syaifakmal/debouncing-and-throttling-on-flutter-265d42eee8d9
Debouncing and Throttling in Flutter using flutter_debouncer 2.0.0
Ever encountered moments when your app’s responsiveness didn’t quite match your expectations? Imagine you’re typing a message or clicking a…
medium.com
'Flutter' 카테고리의 다른 글
Flutter 신용카드 예제 Like 카카오페이 2편 (0) | 2025.03.05 |
---|---|
Flutter Papago API 를 활용한 번역 서비스 만들기 (1) | 2025.02.26 |
Flutter 신용카드 예제 Like 카카오페이 1편 (1) | 2025.02.19 |
Flutter 의 annotation 에 대해 (0) | 2025.02.12 |
Flutter Firebase Crashlytics 적용해보기 (0) | 2025.02.06 |