IMCAT.DEV
로그인 가입
Dart 중급 비동기

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. 정리

  1. 비동기 프로그래밍은 사용자 경험을 향상시키고, 효율적인 코드 작성을 가능하게 합니다.
  2. Future와 Stream은 각각 단일 값과 여러 값의 비동기 처리를 도와줍니다.
  3. 비동기 처리를 잘 활용하면, 서버 요청과 같은 시간이 걸리는 작업을 효율적으로 처리할 수 있습니다.
  4. 다음 주제로는 비동기 프로그래밍 패턴인 async/await와 예외 처리에 대해 학습하는 것을 추천합니다.