Flutter Study Day 11 Dart async & callback

정정원·2023년 12월 13일
0

Flutter Study

목록 보기
13/17

비동기 프로그래밍

임의의 순서로 또는 동시에 작업이 실행될 수 있다.
비동기를 처리하는 방법에는 콜백, Future, async - await 방식이 있다.

동기 프로그래밍

코드가 순서대로 실행된다.
작업이 완료될 때까지 프로그램이 중단될 수 없다.
모든 작업은 이전 작업의 실행이 완료될 때까지 기다려야 한다.

동기와 비동기



callback 함수

콜백은 실행 가능한 함수를 인자로 전달하여, 특정 상황이 발생할 때 호출되게 하는 방식이다.

현실 세계에서 콜백의 예시 :
음식을 주문하고 진동벨을 가지고 기다리면 음식이 준비되면 손님을 호출(Callback)하는 상황

콜백 함수 작성

회원가입의 3단계

  1. 회원 가입 API 호출
  2. DB에 저장
  3. 이메일 전송
  4. 성공 메시지 출력
final List database = [];

void main(List<String> arguments) {
 final result = register({
   'email': 'abc@abc.com',
   'password': '123456',
   'name': 'John Doe',
 });
 print(result.call());
 print(database);
}

Function register(user) {
 return saveDb(user, (user) {
   return sendEmail(user, (user) {
     return getResult(user);
   });
 });
}

Function saveDb(user, callback) {
 print('saving $user to db');
 return callback(user);
}

Function sendEmail(user, callback) {
 print('sending email to $user');
 database.add(user);
 return callback(user);
}

Function getResult(user) {
 return () => 'success register $user';
}

실행 결과

saving {email: abc.com, password: 123456, name: John Doe} to db
sending email to {email: abc.com, password: 123456, name: John Doe}
success register {email: abc.com, password: 123456, name: John Doe}
[{email: abc.com, password: 123456, name: John Doe}]

콜백지옥

비동기 처리 로직을 위해 콜백 함수를 연속해서 사용할 때 발생하는 문제.

Future

미래에 완료되는 객체
Javascript 의 Promise 에 대응
Future 는 ‘미래'에 받아올 값을 의미

Future<String> name;
Future<int> number;
Future<Person> person;

Dart 및 Flutter 의 많은 API 는 Future 타입을 리턴한다.
다음 코드는 비동기 코드를 시뮬레이트하기 위해 5 초 후에 실행되는 Future 함수를 정의한 것이다.

var delay = Future.delayed(Duration(seconds:5));
//2초 미래에 동작하는 코드 작성 예
void myFunction() {
	print('start');
  	
    Future.delayed(Duration(seconds: 2), () {
    	print('2 seconds');
    }); // Future.delayed
	print('end');
}

Future 타입 변경

Future 함수는 함수 본문 앞에 async키워드를 지정해 줘야 한다.
대기하고 싶은 비동기 함수를 실행할 때 await 키워드를 사용해주면 코드를 작성한 순서대로 실행된다.

//회원가입 3단계 함수들을 Future 타입을 변경

Future<void> saveDb(user) async{
	print('saving $user to db');
}

Future<void> sendEmail(user) async{
	await Future.delayed(Duration(seconds: 2));
    print('sending email to $user');
    database.add(user);
}

Future<void> getResult(user) async{
	return 'success register $user';
}

then() 함수

Future 함수는 결과를 then() 함수를 통해서 받을 수 있다.
then() 함수로 전달되는 콜백 함수에 다음에 실행할 코드를 작성하면 된다.
다음 코드가 Future라면 계속해서 then() 을 이어서 결과를 전달받을 수 있다.
불필요한 인자는 _ 를 쓰는 것이 관례이다.

//회원가입 3단계 함수들을 Future 타입을 변경

final user = {
	'email' : 'abc@abc.com'
    'password' : '123456'
    'name' : 'John Doe'
};

saveDb(user)
	.then((_) => sendEmail(user))
    .then((_) => getResult(user))
    .then((value) => print(user));

Future 핸들링

Future 는 성공(then)일 수도 있고 오류(catchError)일 수도 있다.

delay
	.then((value) => print('I have been waiting'))
    .catchError((err) => print(err));

Future 예외 처리

catchError() 함수를 사용하면 에러 처리를 할 수 있다
에러를 발생시킬 때는 Future.error() 를 사용한다.

throw Exception() 으로 예외를 발생시킬 수 있다.

then() 사용의 문제점

  • 확실히 콜백 보다는 편하지만 동기식 코드 보다는 결과 예측이 어렵다.
  • 단계가 많아지면 then() 을 연결하는 체이닝 방식을 사용하는 것이 만만치 않다.
  • 로직이 복잡해 지면 적절한 예외처리하기에 용이하지 않다.
  • 궁금하다면 최대한 복잡한 코드를 찾아보자.

async - await 문법

async - await 는 비동기 코드를 작성할 때 더 깔끔한 코드를 제공한다.
await 키워드는 해당 Future 가 끝날 때까지 함수 실행을 기다린다.

Future<String> runInTheFuture() async {
	var data = await Future.value('world');
    
    return 'hello $data';
}
//async - await 를 사용한 이메일 보내기 3단계

//등록 과정을 깔끔하게 작성했다.
Future<String> register(user) async {
	await saveDb(user);
    await sendEmail(user);
    return await getResult(user);
}

//main() 함수도 async 를 붙이면 await를 사용할 수 있다.
void main(List<String> arguments) async {
	final user = {
    	'email' : 'abc@abc.com'
    	'password' : '123456'
    	'name' : 'John Doe'
    };
    
    final result = await register(user);
    print(result);
}

병렬처리

병렬 처리는 동시에 여러가지 일을 진행하는 것이다.
Future 함수는 await 없이 사용하면 동시에 여러개를 실행할 수 있다.

비동기 & 콜백 정리

  1. await 키워드 뒤에는 반드시 Future 타입이 와야 한다.
  2. await 키워드는 async 키워드가 있는 함수에서만 사용할 수 있다.
  3. 에러처리나 가독성, 처리상황에 따라 적절한 코드를 잘 선택할 수 있어야 한다.

0개의 댓글