특정 작업이 5초 이내에 완료되지 않으면 예외 처리하기
예를 들어, 서버에서 데이터를 가져오는 작업이나, UI의 특정 이벤트가 발생할 때까지 기다리는 작업을 수행할 때 최대 대기 시간을 설정하고 싶을 수 있다. 이때 바로 Future.timeout을 사용해보자
기본 사용법
Future<void> fetchDataWithTimeout() async {
try {
await Future.delayed(const Duration(seconds: 6)) // 6초 후에 완료
.timeout(const Duration(seconds: 5)); // 타임아웃 5초 설정
print('✅ 작업 성공');
} catch (e) {
print('⏳ 작업이 5초 안에 완료되지 않음: $e');
}
}
위 코드에서 Future.delayed(Duration(seconds: 6))는 6초 후에 완료되는 가상의 작업을 설정한다. 그리고 timeout(Duration(seconds: 5))을 설정해서 5초가 초과되면 예외가 발생하게한다.
출력 결과:
⏳ 작업이 5초 안에 완료되지 않음: TimeoutException after 0:00:05.000000
Completer와 timeout을 함께 사용하기
Completer를 함께 사용하면 단순한 Future.timeout보다 더 유연한 비동기 작업 제어가 가능하다. 특히, 여러 개의 비동기 작업 중 가장 빠른 응답을 선택할 수 있고, 특정 시점에서 명시적으로 완료하거나 에러를 커스텀 핸들링할 수 있다. 또한, 타임아웃 외에도 재시도, 취소, 병렬 처리 등의 정교한 제어가 가능하며, 실무에서 동시 요청 처리와 UX 최적화에 유용하다.
Completer와 timeout을 함께 사용한 코드 예제
import 'dart:async';
import 'package:http/http.dart' as http;
Future fetchData() {
final completer = Completer();
http.get(Uri.parse('https://jsonplaceholder.typicode.com/todos/1')).then(
(response) {
if (!completer.isCompleted) completer.complete(response.body);
},
).catchError((error) {
if (!completer.isCompleted) completer.completeError(error);
});
return completer.future.timeout(
const Duration(seconds: 3),
onTimeout: () => throw '⏳ 요청 시간이 초과되었습니다!',
);
}
void main() async {
try {
final data = await fetchData();
print('✅ 데이터 가져오기 성공: $data');
} catch (e) {
print('🚨 오류 발생: $e');
}
}
- HTTP 요청을 보내고 Completer로 응답을 제어
- 성공하면 completer.complete(response.body), 실패하면 completer.completeError(error)
- timeout(3초)을 설정하여 시간 초과 시 예외 발생
- onTimeout 콜백을 활용해 타임아웃 시 '⏳ 요청 시간이 초과되었습니다!' 오류 발생
- main 함수에서 실행 후 결과 출력
- 성공 시 데이터 출력, 실패 또는 타임아웃 시 예외 메시지 출력
출력 결과:
✅ 데이터 가져오기 성공: {
"userId": 1,
"id": 1,
"title": "delectus aut autem",
"completed": false
}
만약 입력이 3초 후에 도착했다면?
🚨 오류 발생: ⏳ 요청 시간이 초과되었습니다!
실전 예제: 네트워크 요청에 타임아웃 적용하기
Completor+timeout 조합을 적용하기 가장 적합한 곳은 네트워크 요청부분이다. 백엔드 API 호출이 느려서 앱이 멈추는 문제를 방지하려면 HTTP 요청에도 timeout을 적용해야 하는데 이때 활용하기 딱좋다.
import 'dart:async';
import 'package:http/http.dart' as http;
Future fetchDataWithHttp() async {
try {
final response = await http
.get(Uri.parse('https://jsonplaceholder.typicode.com/todos/1'))
.timeout(const Duration(seconds: 3)); // 3초 타임아웃 설정
print('✅ 데이터 가져오기 성공: ${response.body}');
} catch (e) {
print('⏳ 네트워크 요청이 3초 내에 완료되지 않음: $e');
}
}
void main() async {
await fetchDataWithHttp();
}
네트워크 요청이 3초 내에 완료되지 않으면 TimeoutException이 발생시킨다
Best Practices
1. 적절한 타임아웃 값 설정
- 네트워크 요청: 3~5초 (API 응답 속도 고려)
- 사용자 입력 대기: 5~10초 (UX 고려)
- 로딩 스피너: 2~5초 (UI 반응성 고려)
2. Completer는 항상 complete()해야 함
- Completer를 사용하면 무조건 complete() 호출이 보장되도록 처리해야 한다.
- 그렇지 않으면 Future가 영원히 대기 상태로 남을 수 있다.
3. 타임아웃 예외를 적절히 처리하기
- catch (e) {} 블록에서 타임아웃 발생 시 대체 로직을 수행해야 한다.
- 예를 들어, 사용자에게 다시 시도하라고 안내하거나, 기본값을 반환하는 방식으로 대응할 수 있다.
'Flutter' 카테고리의 다른 글
Theme.of(context) 사용시 주의할 점 (0) | 2025.02.11 |
---|---|
Freezed 패키지에서 Equatable 패키지로 바꾼 이유 (0) | 2025.02.10 |
조건부 처리 - 삼항 연산자, switch, if 문 중 어떤걸 쓸까 (작성중) (0) | 2025.02.06 |
Flutter에서 Stomp로 소켓통신하기 (2) | 2025.02.05 |
어떻게 플러터는 변경된 위젯만 콕찝어서 다시 페인팅할 수 있는걸까? (0) | 2025.02.02 |