Future은 비동기 작업을 처리하는 데 사용되는 클래스입니다.
비동기 작업은 즉시 완료되지 않고 일정 시간이 걸리는 작업을 말하며, Future는 이러한 작업의 완료 또는 실패 결과를 나타내는 객체입니다.
여기서 동기와 비동기란
비동기 (asynchronous) / 동기 (synchronous)
위 사진을 참고하여 보면
- 동기 (Synchronous)
- 한 작업이 완료될 때까지 다음 작업이 시작되지 않습니다.
- 간단하고 직관적이지만, 시간이 오래 걸리는 작업일 경우 비효율 적입니다.
void main() {
print('시작');
performTask();
print('끝');
}
void performTask() {
print('실행중');
}
// 차례대로 출력
시작
실행중
끝
- 비동기 (Asynchronous)
- 한 작업이 진행되는 동안 다른 작업을 동시에 실행할 수 있습니다.
- 복잡하지만 시간소모가 적어 효율적입니다.
void main() async {
print('시작');
await performTask();
print('끝');
}
Future<void> performTask() async {
await Future.delayed(Duration(seconds: 2));
print('실행중');
}
// 차례대로
시작
(2초 기다림)
실행중
끝
로 볼수 있습니다. 그리고 위 코드에서
void main() async {
print('시작');
await performTask();
print('끝');
}
performTask() async {
await Future.delayed(Duration(seconds: 2));
print('실행중');
}
위 코드처럼 Future<void>는 생략할 수 있습니다.
Dart에서는 async 키워드를 보고 자동으로 Future<>로 간주합니다.
허나, Future<void> 처럼 반환타입을 명시하는 것이 코드를 읽을 때 Future를 반환하는 것을 정확히 알 수 있기 때문에
적어 주는게 좋습니다.
Future
Future는 비동기 함수가 호출될 때 반환됩니다.
보통은 async/await와 함께 사용하지만 Future 단독으로도 사용될 수 있습니다.
함수 가장앞에 반환 타입과 함께 표기됩니다.
Future<String> performTask() {
return Future.delayed(Duration(seconds: 2), () {
return '실행중';
});
}
async / await
async / await 키워드를 사용하면 비동기 코드를 더 쉽게 작성할 수 있습니다.
async 함수는 항상 Future를 반환하며
await 키워드는 해당 Future가 완료될 때까지 기다립니다.
void main() async {
print('시작');
String result = await performTask();
print(result);
print('끝');
}
- async는 함수의 ()소괄호와 {}중괄호 사이에 입력하여야 합니다.
- await는 기다려야할 변수 앞에 키워드를 입력하여야 합니다.
- 두 개의 키워드는 함께 쓰여야 기능합니다.
여기서 드는 의문은 언제 어떻게 Future와 async/await를 사용하느냐입니다.
// async/await사용안함, return있음
void main() async {
print('시작');
String result = await performTask();
print(result);
print('끝');
}
Future<String> performTask() {
return Future.delayed(Duration(seconds: 2), () {
return '실행중';
});
}
// async/await사용함, return없음
void main() async {
print('시작');
await performTask();
print('끝');
}
Future<void> performTask() async {
await Future.delayed(Duration(seconds: 2));
print('실행중');
}
// async/await사용안함, return없음
void main() {
print('시작');
performTask().then((result) {
print(result); // '실행중' 출력
print('끝');
});
}
Future<void> performTask() {
return Future.delayed(Duration(seconds: 2)).then((_) {
print('실행중');
});
}
이 세 개의 코드는 똑같은 결과를 내놓습니다.
위 코드에서 Future는 async/await를 사용하지 않았고, String값인 '실행중'을 반환하도록 돼있습니다.
가운데 코드에서 Future는 async/await를 사용하였고, void로 아무것도 반환하지 않도록 돼있습니다.
아래 코드에서 Future는 async/await를 사용하지 않았고, void로 아무것도 반환하지 않도록 돼있습니다.
(then 함수는 Future 객체가 내포하고 있는 메서드로, 비동기 작업이 완료되었을 때 실행할 콜백 함수를 지정하는 데 사용됩니다.
then은 Future가 성공적으로 완료된 후에 호출되며, 완료된 Future의 결과를 콜백 함수의 인수로 전달합니다.)
결론을 말씀드리자면
- async/await 사용
- async와 await 키워드는 비동기 작업의 순서를 명확하게 하고, 코드의 가독성을 높이는 데 도움을 줍니다.
- 그러므로 복잡한 비동기 로직을 처리할 때는 async와 await를 사용하는 것이 더 직관적이고 유연합니다.
- Future만 사용
- 단순한 비동기 작업에서는 Future 객체와 콜백 함수를 직접 사용하여 async와 await 없이 작성할 수 있습니다.
이렇듯 코드의 구성차이이며 복잡하거나 코드의 가독성을 높일 땐 async/await를 사용합니다.
왜 비동기 프로그래밍을 하는가
대표적으로 파일 읽기/쓰기, 네트워크 요청 등이 있습니다.
예를 들어
Image.network("https://blahblah.png")
이와 같은 코드는 네트워크를 통해 이미지를 불러오는 코드를 작성한다 하였을 때
비동기 형식을 사용한다면 화면에서 버튼, 상하단바는 다 보이는 상황인데 이미지만 보이지 않은 상황이 됩니다.
이를 비동기 작업을 하여 동기화를 시켜
Future<Image> loadImage() async {
return Image.network(
"https://blahblah.png",
);
}
이미지의 로드가 완료될 때까지 나머지 작업을 멈출 수 있습니다.
'Flutter > Dart Language' 카테고리의 다른 글
[플러터 flutter] initState와 dispose란? (0) | 2024.07.31 |
---|---|
[플러터 Flutter] 예외처리 try-catch와 throw, finally (1) | 2024.07.16 |
[플러터 Flutter] 초기화란? (0) | 2024.06.29 |
[플러터 Flutter] Const, Final의 차이 그리고 컴파일타임과 런타임 (0) | 2024.06.29 |
[플러터 Flutter] Null-Safety와 late키워드 (0) | 2024.06.29 |