데이터를 처리하는 방식에는 동기(synchronous)와 비동기(asynchronous)가 존재한다.
동기 방식은 요청을 보내고 응답이 돌아와야 다음 동작을 수행할 수 있다.
반면, 비동기 방식은 요청을 보내고 응답이 돌아오지 않아도 다음 동작을 수행할 수 있다.
동기 방식은 직관적이지만 응답이 돌아올 때까지 기다려야하므로 시간이 많이 소모되는 단점이 있다. 비동기 방식은 프로그램이 요청받은 일을 수행하는 동안 계속 다음 동작을 수행할 수 있으므로 데이터를 fetch하거나, 파일에서 데이터를 읽어오는 등의 작업을 할 때에 사용된다.
플러터에는 비동기 방식을 처리하기 위한 특수한 키워드가 존재한다. 대표적으로 Future가 있고, 다른 언어에도 사용되는 async, await가 있다.
future은 Future 클래스의 객체로, 비동기 작업의 결과를 나타낸다.
uncompleted와 completed 상태를 가진다.
uncompleted
비동기 함수를 호출했을 때, 그 결과로 uncompleted 상태의 future를 return한다. 해당 future은 함수의 비동기 작업이 끝나거나 에러가 발생하는 걸(throw an error) 기다린다.
completed
비동기 작업이 끝나면, 해당 future은 값을 가지게 된다.
에러가 발생하지 않았다면, Future에서 T 타입의 값을 가지게 된다.
future 예시
다음은 Future를 사용한 비동기 처리의 예시이다.
Future<void> fetchUserOrder() {
return Future.delayed(const Duration(seconds: 2), () => print('Large Latte'));
}
void main() {
fetchUserOrder();
print('Fetching user order...');
}
해당 코드를 실행하면, 코드 순서와는 다르게 Fetching user order...가 먼저 출력되고, 2초 뒤 Large Latte가 출력된다.
async와 await 키워드는 비동기 함수를 정의하고 비동기 처리를 하는데 사용된다.
async 키워드를 함수 앞에 붙이면 비동기 함수를 정의할 수 있고, await 키워드는 비동기 함수 안에서만 사용 가능하다.
String createOrderMessage() {
var order = fetchUserOrder();
return 'Your order is: $order';
}
Future<String> fetchUserOrder() =>
// Imagine that this function is
// more complex and slow.
Future.delayed(
const Duration(seconds: 2),
() => 'Large Latte',
);
void main() {
print('Fetching user order...');
print(createOrderMessage());
}
위 코드를 실행하면, Fetching user order...가 출력된 뒤 Your order is: Instance of '_Future'가 출력된다. 이는 createOrderMessage 함수가 동기 처리가 되어서 그렇다.
Future<String> createOrderMessage() async {
var order = await fetchUserOrder();
return 'Your order is: $order';
}
Future<String> fetchUserOrder() =>
// Imagine that this function is
// more complex and slow.
Future.delayed(
const Duration(seconds: 2),
() => 'Large Latte',
);
Future<void> main() async {
print('Fetching user order...');
print(await createOrderMessage());
}
위 코드를 실행하면 Fetching user order...가 출력된 뒤 Your order is: Large Latte가 잘 출력되는 것을 확인할 수 있다.
비동기 함수에서 에러를 처리할 때, try-catch문을 사용한다.
Future<void> printOrderMessage() async {
try {
print('Awaiting user order...');
var order = await fetchUserOrder();
print(order);
} catch (err) {
print('Caught error: $err');
}
}
Future<String> fetchUserOrder() {
// Imagine that this function is more complex.
var str = Future.delayed(
const Duration(seconds: 4),
() => throw 'Cannot locate user order');
return str;
}
void main() async {
await printOrderMessage();
}
https://dart.dev/codelabs/async-await
https://velog.io/@daybreak/%EB%8F%99%EA%B8%B0-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%B2%98%EB%A6%AC