학습
Dart 비동기 프로그래밍 (Future, Stream)
Dart 비동기 프로그래밍 (Future, Stream) — 중급
비동기 프로그래밍 (Future, Stream)
1. 도입 (왜 배워야 하는가)
비동기 프로그래밍은 현대 소프트웨어 개발에서 매우 중요한 개념입니다. 특히 Dart와 같은 언어에서는 비동기 작업을 통해 사용자 경험을 향상시킬 수 있습니다. 예를 들어, 웹 애플리케이션을 개발할 때 서버로부터 데이터를 받아오는 작업이 동기적으로 진행된다면, 사용자는 그 동안 아무런 반응을 받지 못하게 됩니다. 이로 인해 사용자는 지루함을 느끼고, 때로는 애플리케이션이 멈춘 것처럼 느낄 수 있습니다.
비동기 프로그래밍을 활용하면 이러한 문제를 피할 수 있습니다. 즉, 사용자 인터페이스(UI)는 다른 작업을 수행하면서 백그라운드에서 데이터를 요청하고, 데이터가 준비되면 그 결과를 UI에 반영할 수 있습니다. 만약 비동기 프로그래밍을 잘 이해하지 못하면, 비효율적인 코드와 느린 사용자 경험으로 이어질 수 있습니다.
2. 핵심 개념 설명
Future
Future는 나중에 완료될 수 있는 작업을 나타내는 객체입니다. 마치 약속을 지키기 위해 기다리는 것과 같습니다. 예를 들어, 친구에게 내일 만나자고 약속했을 때, 그 약속이 지켜질지 안 지켜질지는 나중에 알 수 있습니다.
Stream
Stream은 여러 개의 값이 순차적으로 발생할 수 있는 데이터를 나타냅니다. 비유하자면, 영화관에서 상영되는 여러 영화들처럼, 영화가 하나씩 차례대로 보여지는 것과 같습니다. 스트림은 지속적인 데이터 흐름을 처리하는 데 유용합니다.
| 용어 | 설명 |
|---|---|
| Future | 단일 값이 나중에 제공될 것임을 나타냄 |
| Stream | 여러 값이 순차적으로 발생할 수 있는 데이터 흐름 |
3. 기본 코드 예제
Future 예제
Future<String> fetchData() async {
return Future.delayed(Duration(seconds: 2), () => "데이터 수신 완료");
}
void main() async {
print("데이터 요청 중...");
String data = await fetchData();
print(data);
}
- 실행 결과:
데이터 요청 중...
(2초 후) 데이터 수신 완료
1. fetchData 함수는 비동기적으로 2초 후에 문자열을 반환하는 Future를 반환합니다.
2. main 함수에서 fetchData를 호출하고, 결과가 준비될 때까지 대기합니다.
3. 데이터가 수신되면 "데이터 수신 완료"를 출력합니다.
Stream 예제
Stream<int> countStream() async* {
for (int i = 1; i <= 5; i++) {
await Future.delayed(Duration(seconds: 1));
yield i;
}
}
void main() async {
print("카운트 시작...");
await for (int count in countStream()) {
print(count);
}
}
카운트 시작...
(1초 후) 1
(1초 후) 2
(1초 후) 3
(1초 후) 4
(1초 후) 5
1. countStream 함수는 1초 간격으로 1부터 5까지의 숫자를 발생시키는 스트림입니다.
2. main 함수에서 countStream을 호출하고, await for를 사용하여 값이 발생할 때마다 출력합니다.
4. 실전 활용 예제
예제 1: 쇼핑몰 장바구니 구현
쇼핑몰에서 장바구니에 상품을 추가할 때, 서버에 요청을 보내고 그 결과를 비동기적으로 처리해야 합니다.
Future<void> addToCart(String productId) async {
print("장바구니에 상품 추가 중...");
await Future.delayed(Duration(seconds: 2)); // 서버 요청 시뮬레이션
print("$productId 상품이 장바구니에 추가되었습니다.");
}
void main() async {
await addToCart("상품123");
}
예제 2: 실시간 채팅
실시간 채팅 애플리케이션에서 메시지를 수신하는 스트림을 사용할 수 있습니다.
Stream<String> messageStream() async* {
for (int i = 1; i <= 3; i++) {
await Future.delayed(Duration(seconds: 1));
yield "메시지 $i 수신됨";
}
}
void main() async {
print("메시지 수신 대기 중...");
await for (String message in messageStream()) {
print(message);
}
}
5. 흔한 실수와 주의사항
실수 1: Future의 결과를 반환할 때 await를 누락
Future<String> fetchData() async {
return "데이터 수신 완료"; // await 누락
}
Future<String> fetchData() async {
await Future.delayed(Duration(seconds: 2));
return "데이터 수신 완료";
}
실수 2: Stream을 제대로 구독하지 않음
Stream<int> countStream() async* {
for (int i = 1; i <= 5; i++) {
await Future.delayed(Duration(seconds: 1));
yield i;
}
}
void main() {
countStream(); // 구독을 하지 않음
}
void main() async {
await for (int count in countStream()) {
print(count);
}
}
6. 정리
- 비동기 프로그래밍은 사용자 경험을 향상시키고, 효율적인 코드 작성을 가능하게 합니다.
Future와Stream은 각각 단일 값과 여러 값의 비동기 처리를 도와줍니다.- 비동기 처리를 잘 활용하면, 서버 요청과 같은 시간이 걸리는 작업을 효율적으로 처리할 수 있습니다.
- 다음 주제로는 비동기 프로그래밍 패턴인
async/await와 예외 처리에 대해 학습하는 것을 추천합니다.