- 비동기 처리를 위해 존재하는 자료형.
- 미래에 처리된 데이터가 담길 그릇. 당장이 아니라 미래에 처리된 데이터를 가지고 어떤 작업을 하기 위해 필요함.
- 네트워크를 통해 요청하고 응답을 받아올 때, 해당 요청을 받을 때까지 앱이 멈추면 안 된다. 따라서 네트워크 요청은 비동기 방식으로 진행됨. 네트워크 요청은 요청대로 흘러가고, 코드 진행은 알아서 내려감. 그 와중에 네트워크 요청의 응답이 온다면? 적절한 조치를 취해야 함. 이를 위해 future가 필요하다.
- 어떠한 기본 함수가 비동기로 동작하는지 비동기로 동작하는지 알고 있어야 앱의 흐름을 제대로 파악할 수 있다.
Future<int> futureNumber() {
// 3초 후 100을 들고 있는 future 리턴
return Future<int>.delayed(Duration(seconds: 3), () {
return 100;
});
}
void main() {
Future<int> future = futureNumber();
future.then((val) {
print('val: $val');
}).catchError((error) {
print('error: $error');
});
print('기다리는 중');
}
- futureNumber 함수 실행.
- futureNumber가 Future를 return함. <-- 중요!
- 기다리는 중 출력.
- future가 100이라는 값을 가진 채로 처리됨.
- 3초 뒤 then이 불리고 100을 출력함.
then에서의 문법
> ()는 future로 감싸서 리턴한 매개변수.
{}에는 그 매개변수를 바탕으로 실행될 함수.
await: 해당 비동기 함수가 처리될 때까지 동기처럼 기다려라.
async: 나는 비동기 함수다!
규칙
1. 어떠한 함수 내부에서 await를 사용했다면, 그 함수는 async여야 한다.
-> 함수 내부에서 future 기다릴 놈이면 그 함수 자체도 비동기 함수로 작성해라. 성능을 위해 비동기를 사용하는데, await 때문에 모든 작업을 멈출 수 없기 때문이다.
2. async 함수는 무조건 future를 반환해야 한다.
-> 비동기 함수는 future를 반환해서 미래에 응답된 데이터를 적절히 처리해라.
void main() {
Future<ProcessedData> data = createData();
print(data);
}
Future<ProcessedData> createData() async {
final id = await _loadFromDisk();
final data = await _fetchNetworkData(id);
return ProcessedData(data);
}
async와 await를 사용하면 then보다 더 직관적이고 간결함.
출력: Instance of 'Future<ProcessedData>
우리는 ProcessedData(data)가 완료된 data를 출력하고 싶다. 근데 createData 함수는 async 함수이기 때문에 처리되기 전에 main에서 출력된다. 이런 경우에 main에서 createData를 호출할 때 await를 사용하면 된다.
void main() {
Future<ProcessedData> data = await createData();
print(data);
}
Future<ProcessedData> createData() async {
final id = await _loadFromDisk();
final data = await _fetchNetworkData(id);
return ProcessedData(data);
}
출력: ProcessedData(data)에 해당하는 값.
대부분의 상황은 대체 가능하지만, then이 필요한 경우도 존재한다.
await는 수행 중인 함수의 동작을 아예 멈추지만, then은 수행 중인 함수의 동작을 멈추지 않고 이후 코드가 계속 실행되기 때문.
Future<String> helloWorld() {
return Future.delayed(Duration(seconds: 3), () {
return "Hello World";
});
}
Future<String> byeByeWorld() {
return Future.delayed(Duration(seconds: 3), () {
return "Bye Bye World";
});
}
Future<List<String>> world() async {
final future1 = await helloWorld();
final future2 = await byeByeWorld();
print('(world) future1: $future1');
print('(world) future2: $future2');
print('(world) future와 관계 없는 print문, 빨리 수행될 수록 좋음');
return [future1, future2];
}
void main() {
final futures = world();
print('(main) future: $futures');
}
실행:
print('(main) future: $futures');
출력:
(main) future: Instance of 'Future<List<String>>' //0초
실행:
print('(world) future1: $future1');
print('(world) future2: $future2');
print('(world) future와 관계 없는 print문, 빨리 수행될 수록 좋음');
출력:
(world) future1: Hello World // 6초
(world) future2: Bye Bye World // 6초
(world) future와 관계 없는 print문, 빨리 수행될 수록 좋음 // 6초
Future<String> helloWorld() async {
return Future.delayed(Duration(seconds: 3), () {
return "Hello World";
});
}
Future<String> byeByeWorld() async {
return Future.delayed(Duration(seconds: 3), () {
return "Bye Bye World";
});
}
List<Future<String>> world() {
final future1 = helloWorld();
future1.then((val) {
print('(world) future1: $val');
});
final future2 = helloWorld();
future2.then((val) {
print('(world) future2: $val');
});
print('(world) future와 관계 없는 print문, 빨리 수행될 수록 좋음');
return [future1, future2];
}
void main() {
final futures = world();
print('(main) future: $futures');
}
실행:
print('(main) future: $futures');
출력:
(main) future: Instance of 'Future<List<String>>' //0초
실행:
print('(main) future: $futures');
출력":
(main) future: [Instance of 'Future<String>', Instance of 'Future<String>'] // 0초
실행:
future1.then((val) {
print('(world) future1: $val');
});
future2.then((val) {
print('(world) future2: $val');
});
출력":
(world) future1: Hello World // 3초
(world) future2: Bye Bye World // 3초
await 때문에 생긴 불필요한 중단을 then을 사용해서 해결할 수 있었다.
https://velog.io/@jintak0401/FlutterDart-%EC%97%90%EC%84%9C%EC%9D%98-Future-asyncawait
https://pcseob.tistory.com/8