한가지 일이 끝나야 다른 일을 하는 사람의 패턴은 첫 번째 그래프와 같고
한가지 일이 끝나기 전에 다른 일을 동시에 하는 사람의 패턴은 두 번째 그래프와 같습니다.
동기: 하나의 일이 끝난 뒤 다음 일을 하는 방식
비동기: 하나의 일이 끝나기 전에 동시에 다른 일을 하는 방식
오래 걸리는 작업을 처리할 때, 사용자 경험을 최적화하기 위해 비동기 방식으로 처리하는 것이 권장됩니다.
예를들어, 사용자가 버튼을 클릭했을 때 데이터를 가져오는 작업이 동기방식으로 실행되면, 그 작업이 완료될 때까지 사용자는 어떠한 다른 작업도 할 수 없게 됩니다. 이는 사용자에게 불편함을 줍니다.
대부분 우리가 작성하는 코드, 특히 UI와 관련된 코드는 동기적으로 작성되며, 사용자의 입력에 따라 순차적으로 실행됩니다.
그러나 네트워크 요청이나 데이터베이스 접근과 같이 응답 시간이 불규칙하거나 지연될 수 있는 작업은 비동기 방식으로 처리하는 것이 일반적입니다.
왜냐하면 네트워크 요청의 응답 시간은 예측하기 어렵고, 여러 요인에 따라 달라질 수 있습니다.
그렇기 때문에 사용자가 오래 기다리게 만드는 것보다, 사용자에게 다른 작업을 할 수 있는 자유를 주는 것이 좋습니다.
HTTP 요청 후 응답을 받아서 화면에 데이터를 표시하는 작업의 경우
비동기 방식으로 이 작업을 처리하게 되면, 요청을 보내고 즉시 응답을 기다리지 않고 다음 코드 라인으로 넘어갑니다.
만약 이 다음 코드 라인이 응답 데이터를 화면에 표시하는 코드라면, 아직 데이터가 도착하지 않았기 때문에 에러가 발생하게 됩니다.
이렇게 비동기 작업 후에 특정 작업을 실행해야 하는 경우에는, 비동기 작업의 결과가 준비될 때까지 기다린 후 해당 작업을 수행하는 동기 방식으로 처리해야 합니다. 이를 위해 비동기 방식으로 동작하는 코드를 동기 방식으로 처리하는 방법을 배워보도록 하겠습니다.
Future.delayed()
Dart에서 Future는 비동기 프로그래밍을 위한 핵심 클래스 중 하나입니다. Future 객체는 어떤 값을 나타내거나 계산의 결과를 반환하는 객체이지만, 그 값이나 계산 결과가 아직 준비되지 않았을 수 있습니다.
Future.delayed()는 주어진 지연 시간 후에 특정 작업을 완료하도록 설정된 Future 객체를 생성합니다. 이는 시뮬레이션, 테스팅, 또는 특정 지연을 유발하는 상황을 모방하는데 유용합니다.
Future<String> fetchData() {
return Future.delayed(Duration(seconds: 3), () => "데이터 로드 완료!");
}
이 코드는 3초의 지연 후에 "데이터 로드 완료!"라는 문자열을 반환하는 Future 객체를 생성합니다.
비동기 함수를 동기 방식으로 처리
Dart에서 비동기 작업을 동기적으로 처리하기 위해 async와 await를 사용합니다.
async는 함수를 선언할 때 사용하여 해당 함수가 비동기 함수임을 나타냅니다. async 함수는 항상 Future를 반환합니다.
await는 async 함수 내에서 사용되며, Future 객체가 완료될 때까지 기다립니다. 이는 비동기 함수를 동기적으로 처리하게 해주는 역할을 합니다.
void main() async {
print('데이터 요청 시작');
String data = await fetchData();
print(data);
print('작업 완료');
}
Future<String> fetchData() {
return Future.delayed(Duration(seconds: 3), () => "데이터 로드 완료!");
}
이 예제에서 main() 함수는 async로 선언되었으므로 await를 사용할 수 있습니다. fetchData() 함수의 반환 값은 Future<String>이지만, await를 사용하여 해당 Future가 완료될 때까지 기다린 후 실제 값을 data 변수에 저장합니다.
결과적으로, 위 프로그램은 다음 순서로 출력됩니다:
1. 데이터 요청 시작
2. (3초 지연)
3. 데이터 로드 완료!
4. 작업 완료
이처럼 async와 await를 사용하면, 비동기 함수를 마치 동기 함수처럼 쉽게 처리할 수 있습니다.