- 동기 : 모든 동작을 차례대로 완료 후 수행하는 것
- 비동기 : 어떤 동작이 완료가 되지 않아도 다음 동작을 수행하는 것
- 비동기 처리를 위해 존재
- Dart의 Future는 지금은 없지만
미래
에 요청한 데이터 혹은 에러가 담길 그릇
< 예시 >
Future<int>
라는 상자가 있다. 지금 당장은 닫혀 있고, 이 상자를 준 함수가 이렇게 말했다.
"언젠가는int
나error
가 나올 것이니 , 두가지 경우를 대비해야 할 것이다."
이 상자를 받은 변수는 상자로부터int
가 나올 때를 대비해then
메소드를 ,error
가 나올 경우를 대비해catchError
메소드를 준비해야 한다.
import 'dart:async';
Future<int> futureNumber() {
// 3초 후 100이 상자에서 나옵니다
return Future<int>.delayed(Duration(seconds: 3), () {
return 100;
});
}
void main() {
// future 라는 변수에서 미래에(3초 후에) int가 나올 것입니다
Future<int> future = futureNumber();
future.then((val) {
// int가 나오면 해당 값을 출력
print('val: $val');
}).catchError((error) {
// error가 해당 에러를 출력
print('error: $error');
});
print('기다리는 중');
}
-> 3초 후에 future
는 int
로 바뀌는 것이 아님 Future<int>
계속해서 유지
그렇다면 어떻게 Future<int>
에서 나오는 값을 다루는 걸까?
--> future.then()
을 통해 다룬다 , val
에 Future<int>
상자가 열렸을 때 나오는 값이 들어갈 것이므로 100 이라고 출력되는 것이다.
비동기로 처리하지 않았다면 Future<int>
에서 값이 나올 때 까지 코드는 실행되지 않고 정지상태로 있을 것이다.
await
키워드를 사용한 함수는 무조건 async
함수이어야 한다.async
함수는 무조건 Future
를 반환해야 한다.Future functionName() async {
...
await someFunction();
...
}
Future<ProcessedData> createData() {
return _loadFromDisk().then((id){
return _fetchNetworkData(id);
}).then((data){
return ProcessedData(data);
})
}
-> 다음 코드는 동기식으로 처리한 코드이다 명령 하나하나가 수행되면 다음단계로 넘어가는 then 을 사용하여 복잡한 코드를 보여준다.
Future<ProcessedData> createDate() async {
final id = await _loadFromDisk();
final data = await _fetchNetworkData(id);
return ProcessedData(data);
}
-> 다음 코드는 비동기식으로 처리한 코드이다. 1번 동기식 코드와 같은 작업을 하는 코드이지만 훨씬 간결하고 보기 좋은 코드이다. 마치 동기적
으로 수행하는 코드인 것 같다.
가장 먼저 첫 번째 줄의 await
키워드가 붙은 _loadFromDisk()
를 수행한다.
await
키워드를 보고 함수의 수행을 멈춘다.
함수를 호출한 곳에 일단은 미리 Future<ProcessedData>
를 return 하고
나중에 함수가 완료되면 ProcessedData
가 나올 것을 알린다.
_loadFromDisk()
함수가 끝날 때 까지 기다리다가 함수의 수행이 완료되면 다음 줄을 수행하고 마찬가지로 await
키워드가 붙은 함수이기 때문에 위 과정과 같은 과정을 반복한다.
마지막으로 return ProcessedData(data) 를 수행하고 호출한 곳에서 미리 return 받았던 Future<ProcessedData>
에서 ProcessedData
가 나오게 된다.
Future<String> helloWorld() {
// 3초 후에 Future<String> 에서 "Hello World" 가 나옵니다
return Future.delayed(Duration(seconds: 3), () {
final hello = "Hello World";
print(hello);
return hello;
});
}
void main() {
final future = helloWorld();
print(future);
}
실행 결과는 다음과 같다
Instance of
'Future<String>'
Hello World
이유가 무엇일까?
출력 순서가 위와 같은 이유는 await
키워드를 사용하지 않았으므로 비동기적으로 처리된다. 따라서 3초가 되기 전에 main
내에 print(future) 가 수행된다.
첫번째 출력이 Instance of 'Future<String>'
인 이유는 future
로 반환된 값은 상자가 열렸을 때 나오는 값으로 바뀌는 것이 아니기 때문이다 future
의 타입은 String
으로 바뀌는 것이 아니라 계속 Future<String>
이다.
Future<String> helloWorld() {
return Future.delayed(Duration(seconds: 3), () {
final hello = "Hello World";
print(hello);
return hello;
});
}
void main() async {
final future = await helloWorld();
print(future);
}
실행 결과는 다음과 같다
Hello World
Hello World
이유가 무엇일까?
-> await
을 사용하지 않았을 때와 달리 await
키워드가 붙은 동작이 완료될 때 까지 함수를 정지시키고 기다리고 해당 동작이 끝나고 나면 곧 바로 결과를 넘겨주기 때문에 Future<String>
으로 String
을 얻을 수 있는 것이다.