[Dart] 비동기 프로그래밍와 예외처리

향신료·2023년 10월 13일
0

🚧 해당 게시글은 FastCampus의 15개 프로젝트로 실무까지 끝내는 Dart & Flutter 앱 개발 강의를 기반으로 작성되었습니다.

강의 링크 👉 https://fastcampus.co.kr/dev_online_dartflutter






비동기


비동기란 코드가 동시다발적으로 진행되는 형태로, 순차적 진행을 보장할 수 없습니다.

사용되는 주요 개념으로 FutureStream이 있습니다.


Future는 단일 비동기 작업의 결과를 나타내는 데, Stream은 여러 값 또는 이벤트의 시퀀스를 나타내는 데 사용됩니다.






Future


1회만 응답을 돌려받는 경우 사용되는 비동기 객체

ex) 서버에 응답을 받는 경우



Future 를 이용하여 비동기 작업을 시작하면 결과는 Future 객체에 저장됩니다.

문제없이 진행된 후의 결과를 받는 then 함수 예외가 발생할 경우를 대비할 수 있는 catchError 함수 등으로 각 결과들에 대한 처리를 정의할 수 있습니다.



Future<int> fetchData() async {
  await Future.delayed(Duration(seconds: 5));
  return 5; // 비동기 작업 결과
}

void main() {
  fetchData().then((result) {
    print('비동기 작업 결과: $result');
  }).catchError((error) {
    print('에러 발생: $error');
  });
}





📍 async , await 는 뭐죠?



async

비동기 함수임을 정의하는 키워드입니다.

정의된 함수는 비동기 작업을 수행할 수 있습니다.

Future<리턴타입> 함수명() async {
  // 비동기 작업을 수행하는 코드
}

// 리턴 타입이 없는 void의 경우 아래와 같이 정의가 가능합니다
void 함수명() async {
  // 비동기 작업을 수행하는 코드
}

await

비동기 함수 내에서 사용되는 키워드입니다.

작업이 완료될 때까지 함수의 실행을 중단하고 대기합니다.

Future<void> fetchData() async { 
  var result = await AsyncFunction();
  // 이후는 AsyncFunction()이 완료된 후 실행
}





📍Future로 동시에 비동기 작업 실행은 불가능한가요?



여러 비동기 작업을 동시에 실행하려면 Future.wait 메서드를 사용하여 구현할 수 있습니다.




Future.wait?

여러 Future 객체를 동시에 실행하고 모든 Future가 완료될 때까지 대기 후, 결과를 한꺼번에 반환하는 메서드입니다.

Future<String> someAsyncFunction1() async {
  await Future.delayed(Duration(seconds: 1));
  return 'Function1';
}

Future<String> someAsyncFunction2() async {
  await Future.delayed(Duration(seconds: 5));
  return 'Function2';
}

void fetchMultipleData() async {
  final results = await Future.wait([someAsyncFunction1(), someAsyncFunction2()]);
   // results에 각 작업의 결과가 저장됨
	print('모든 작업 완료: $results');
}









Stream


지속적으로 응답을 돌려받는 경우 혹은 이벤트의 시퀀스 처리에 사용되는 비동기 객체

ex) 타이머와 같이 지속적으로 일정주기로 반복해야 하는 경우



Stream은 스트림을 생성하고 각 값 또는 이벤트가 도착할 때마다 처리할 수 있기 때문에 실시간 이벤트 처리, 스트리밍 데이터 및 대용량 데이터 처리에 유용합니다.



Stream<int> countStream() async* {
  for (int i = 0; i <= 10; i++) {
    await Future.delayed(Duration(seconds: 1));
    yield i; // 스트림에 값 전달
  }
}

void getStream() async {
  await for (int count in countStream()) {
    print('스트림 값: $count');
  }
}








📍 async* , yield 는 뭐죠?



async*

스트림을 생성하고 async와 같이 값을 하나씩 전달할 수 있는 제너레이터 비동기 함수임을 정의할 때 사용되는 키워드입니다.


Stream<리턴타입> 함수명() async* {
  // 비동기 작업 코드
}

yield

async* 함수 내에서 스트림으로 값을 전달할 때 사용되는 키워드입니다.

return 과 같은 역할을 한다고 볼 수 있습니다.








예외처리


프로그램이 진행 중일 때, 의도하거나 의도치 않은 상황에서 오류가 발생했을 때 대처하기 위한 기능입니다.

프로그램 안정성 유지와 오류 관리에 중요한 역할을 하며, 적절한 처리를 통해 오류를 대처하고 필요에 따라서 사용자에게 오류 메시지를 제공할 수 있습니다.





try-catch문

가장 자주 쓰이는 기본적인 예외처리문

try 블록 내에서 예외가 발생할 수 있는 코드를 감싸고, catch 블록에서 예외를 처리하며 해당 catch는 타입을 가리지 않습니다.


try {
  // 예외가 발생할 수 있는 코드
} catch (e) {
  print("예외가 발생했습니다: $e");
}



on 문

특정 에러 타입을 잡을 때 사용되는 예외처리문

중복으로 사용 가능하기에 에러 타입에 따라 각기 다른 처리를 할 수 있습니다.


try {
  // 예외가 발생할 수 있는 코드
} on Exception1 catch (e) {
  // Exception1 유형의 예외 처리
} on Exception2 catch (e) {
  // Exception2 유형의 예외 처리
} catch (e) {
  // 다른 모든 예외 유형을 처리
}


finally 문

try - catch와 함께 사용하는 예외처리문

예외가 발생했던 하지 않았던, try - catch 이후 반드시 코드를 실행할 때 사용합니다.

try {
  // 예외가 발생할 수 있는 코드
} catch (e) {
  // 예외 처리
} finally {
  // 항상 실행되는 코드
}



throw 문

예외(에러)를 만들어서 던지는 키워드

사용자 정의 에러를 발생시킬 수 있으며, 잘 사용한다면 코드가 의도하지 않은 방향으로 진행되는 것을 방지할 수 있습니다.

void myFunction() {
  // 예외 발생
  throw Exception('사용자 정의 예외');
}


rethrow 문

이미 catch한 에러를 재발생 시키는 작업을 하는 키워드.

try {
  // 예외가 발생할 수 있는 코드
} catch (e) {
  // 예외 처리
  rethrow; // 현재 예외를 다시 발생
}
profile
드문드문 기초 정보를 올리는 블로그

0개의 댓글