본문 바로가기
Dart/Dart Programming language

[중급] Dart 비동기 프로그래밍/ Future와 async/await 기본 개념 이해하기

by Maccrey Coding 2024. 9. 6.
반응형

 

 

비동기 프로그래밍은 현대 애플리케이션 개발에서 필수적인 개념입니다.

Dart는 비동기 작업을 쉽게 관리할 수 있도록 Future 클래스와 async/await 키워드를 제공합니다.

이 글에서는 Future와 async/await의 기본 개념을 설명하고, 이를 어떻게 활용할 수 있는지 예제를 통해 알아보겠습니다.

1. 비동기 프로그래밍이란?

비동기 프로그래밍은 코드가 즉시 실행되는 것이 아니라, 시간이 걸리는 작업이 완료될 때까지 기다리지 않고 다른 작업을 수행할 수 있도록 합니다.

이는 특히 I/O 작업(네트워크 요청, 파일 읽기/쓰기 등)이나 타이머 작업과 같은 상황에서 유용합니다.

비동기 작업이 완료되면 결과를 받아 처리하는 방식입니다.

2. Future 클래스 이해하기

Dart에서 비동기 작업은 Future 객체로 나타납니다. Future는 미래에 완료될 작업의 결과를 나타내며, 아직 결과가 준비되지 않았을 때도 사용할 수 있습니다. Future는 세 가지 상태를 가질 수 있습니다.

  • Uncompleted: 비동기 작업이 아직 완료되지 않은 상태입니다.
  • Completed with a value: 작업이 성공적으로 완료되어 값이 반환된 상태입니다.
  • Completed with an error: 작업이 실패하여 에러가 발생한 상태입니다.

2.1 Future 생성과 사용

Future 객체는 여러 방법으로 생성할 수 있습니다. 가장 기본적인 방법은 Future 생성자를 직접 호출하는 것입니다.

Future<String> fetchData() {
  return Future.delayed(Duration(seconds: 2), () => 'Hello, Dart!');
}

void main() {
  print('Fetching data...');
  fetchData().then((value) {
    print('Received: $value');
  }).catchError((error) {
    print('Error: $error');
  });
}

위 코드에서는 fetchData 함수가 2초 후에 'Hello, Dart!' 문자열을 반환하는 Future를 생성합니다.

then 메서드는 Future가 완료된 후 호출되며, catchError 메서드는 오류가 발생했을 때 호출됩니다.

2.2 then과 catchError를 사용한 비동기 처리

then과 catchError 메서드를 사용하면 Future가 완료된 후의 작업을 처리할 수 있습니다.

fetchData().then((value) {
  print('Received: $value');
}).catchError((error) {
  print('Error: $error');
});

이 방법은 간단하지만, 복잡한 비동기 흐름에서는 코드가 난해해질 수 있습니다. 이를 개선하기 위해 Dart에서는 async와 await 키워드를 제공합니다.

3. async와 await 이해하기

async와 await 키워드는 비동기 코드를 동기 코드처럼 작성할 수 있도록 도와줍니다.

async는 함수가 Future를 반환하도록 하고, await는 Future가 완료될 때까지 기다립니다.

3.1 async와 await 사용법

아래는 async와 await를 사용한 비동기 코드의 예시입니다.

Future<void> fetchData() async {
  print('Fetching data...');
  try {
    String result = await Future.delayed(Duration(seconds: 2), () => 'Hello, Dart!');
    print('Received: $result');
  } catch (e) {
    print('Error: $e');
  }
}

void main() {
  fetchData();
}

위 코드에서 fetchData 함수는 async로 선언되어 있으며, await 키워드를 사용하여 Future가 완료될 때까지 기다립니다.

이 방식은 동기 코드와 유사한 흐름을 제공하여 가독성을 높여줍니다.

3.2 비동기 함수의 반환 타입

비동기 함수는 항상 Future를 반환합니다. 만약 함수가 값을 반환해야 한다면, 해당 값은 Future로 감싸져 반환됩니다.

Future<String> fetchData() async {
  await Future.delayed(Duration(seconds: 2));
  return 'Hello, Dart!';
}

이 경우 fetchData 함수는 Future<String> 타입을 반환합니다.

4. async/await와 Future의 조합

async/await와 Future는 Dart에서 강력한 비동기 프로그래밍 도구입니다.

이 둘을 조합하여 복잡한 비동기 작업을 깔끔하고 효율적으로 처리할 수 있습니다.

여러 개의 비동기 작업을 연속적으로 처리하거나, 병렬로 실행한 후 모든 작업이 완료되기를 기다리는 등의 작업을 쉽게 구현할 수 있습니다.

4.1 여러 Future 병렬 실행

Future.wait를 사용하면 여러 비동기 작업을 병렬로 실행하고, 모든 작업이 완료될 때까지 기다릴 수 있습니다.

Future<void> fetchMultipleData() async {
  try {
    List<String> results = await Future.wait([
      Future.delayed(Duration(seconds: 2), () => 'Data 1'),
      Future.delayed(Duration(seconds: 3), () => 'Data 2'),
      Future.delayed(Duration(seconds: 1), () => 'Data 3'),
    ]);
    print('Received: $results');
  } catch (e) {
    print('Error: $e');
  }
}

void main() {
  fetchMultipleData();
}

위 코드에서는 세 개의 Future가 병렬로 실행되며, 모든 작업이 완료된 후 결과가 리스트로 반환됩니다.

5. 에러 처리와 비동기 코드의 안정성

비동기 작업에서 에러가 발생할 수 있으므로, 항상 에러 처리에 신경 써야 합니다.

async/await를 사용할 때는 try-catch 블록을 사용하여 예외를 처리할 수 있습니다.

Future<void> fetchData() async {
  try {
    String result = await Future.delayed(Duration(seconds: 2), () {
      throw 'Network error';
    });
    print('Received: $result');
  } catch (e) {
    print('Error: $e');
  }
}

이 코드에서는 Future 내에서 예외가 발생했을 때 이를 catch 블록에서 처리합니다.

이를 통해 프로그램이 비정상 종료되지 않고 에러를 우아하게 처리할 수 있습니다.

 

Future와 async/await는 Dart에서 비동기 프로그래밍을 처리하는 데 필수적인 도구입니다.

Future는 비동기 작업의 상태와 결과를 나타내며, async/await 키워드를 사용하면 비동기 작업을 더 직관적이고 읽기 쉽게 작성할 수 있습니다.

이 두 개념을 잘 이해하고 활용하면, 복잡한 비동기 로직도 쉽게 구현할 수 있습니다.

구독!! 공감과 댓글은 저에게 큰 힘이 됩니다.

Starting Google Play App Distribution! "Tester Share" for Recruiting 20 Testers for a Closed Test.

 

Tester Share [테스터쉐어] - Google Play 앱

Tester Share로 Google Play 앱 등록을 단순화하세요.

play.google.com

 

 

반응형