๋ค์ด๊ฐ๊ธฐ ์์
๊ทธ๋์ Flutter๋ก ๊ฐ๋ฐ์ ํด์ค๋ฉด์
Future๋ฅผ ๋ง์ด ์ฌ์ฉํด๋ณด์๋๋ฐ, ์๊ฐ๋ณด๋ค ์ด๋ป๊ฒ ๋์ํ๋์ง ์๊ตฌ์ฌ์ ๊ฐ์ง๋ฉด์ ์ฝ๋ฉํ์ง ์์๋ค.
๋จ์ํ๊ฒ await๋ฅผ ์ฐ๋ฉด ๊ธฐ๋ค๋ฆฌ๊ณ Future๋ฅผ ์ฌ์ฉํ๋ฉด ์ผ๋จ ์๋ ๊ธฐ๋ค๋ฆฌ๋ฉด ๋์ค์ ๊ฐ์ ์ฃผ๋ ์๊ตฌ๋ ๋ผ๊ณ ๋ง์ฐํ๊ฒ ์๊ฐํ๋ค.
์ด๋ฒ ๊ธฐํ์ ์์ธํ ์์๋ณด๋ฉด์ ๊ทธ์ ๋ํ ๊ณต๋ถ ๋ด์ฉ์ ์ ๋ฆฌํ๊ณ ์ ํ๋ค.
1. Dart์ ๋น๋๊ธฐ ๋์ ์๋ฆฌ
Dart๋ ์ฑ๊ธ ์ค๋ ๋๋ก ์ด์๋๋ ์ธ์ด์ด๋ค.
Dart์์ Future๊ฐ ์๋ค๋ฉด ์๋ฐ์คํฌ๋ฆฝํธ์์๋ Promise๊ฐ ์๋ค, ๋๋ค ์ฑ๊ธ ์ค๋ ๋๋ก ๋์์ด ๋๋ค.
๊ทธ๋ ๋ค๋ฉด ์ฑ๊ธ ์ค๋ ๋๋ ์ด๋ป๊ฒ ๋์์ ํ๋ ๊ฒ์ผ๊น?
for(int i=0; i<1000; i++){
print(i);
}
.. next code
์์๊ฐ์ ์ฝ๋๊ฐ ์๋ค๊ณ ํ๋ค๋ฉด
next code๊ฐ ์คํ๋๊ธฐ ์ํด์๋ผ๋ฉด, for๋ฌธ์ด 1000๋ฒ ๋์ํ๊ณ ์ข ๋ฃ๊ฐ ๋ ํ์๋ ๋ค์์ฝ๋๊ฐ ์คํ๋ ๊ฒ ์ด๋ค.
์ฆ ํ๋์ ์ค๋ ๋๋ฅผ ๊ฐ์ง๊ณ ์ฝ๋๊ฐ ์์ฐจ์ ์ผ๋ก ์คํ๋๋ ๊ฒ์ด๋ค.
ํ์ง๋ง ์ด๋ ๊ฒ ๋์์ ํ๋ค๋ฉด, ํ๋ฌํฐ์์๋ UI๋ ๋ ๋๋งํด์ผํ๊ณ ์๋ฒ์์ ๊ฐ๋ ๋ฐ์์ผ ํ ํ ๋ฐ
์์ฒ๋ผ๋ง ๋์ ํ๋ค๋ฉด ํ๋ฉด์ ๊ทธ๋ฆฌ๋ ๋์ค์ ๋ฉ์ถฐ๋ฒ๋ฆด ๊ฒ์ด๋ค.
ํ์ง๋ง ์ค์ ๋ก ํ๋ฌํฐ๋ก ์ ์๋ ์ฑ์ ๋ณด๋ฉด ๊ทธ๋ฌ์ง ์๋๋ค. ๊ทธ๋ ๋ค๋ฉด ์ด๋ป๊ฒ ์ด๊ฒ ๊ฐ๋ฅํ ๊ฒ ์ผ๊น?
์ผ๋จ Dart์์ ์ด๋ป๊ฒ ๋์ํ๋์ง ์์ธํ ์์๋ณด์.
2. Event loop๋?
๋ง์ฝ ์ฐ๋ฆฌ๊ฐ Flutter์ฑ์ ์คํ์ํค๋ ์๊ฐ
isolate๋ผ๋ ์๋ก์ด ํ๋ก์ธ์ค๊ฐ ์คํ์ด ๋๊ณ ์ด ์ค๋ ๋๋ ์ฑ ์ ์ฒด๋ฅผ ์ด๊ดํ๋ ์ ์ผํ ๋จ์ผ ์ค๋ ๋๊ฐ ๋๋ค.
์ด ์ค๋ ๋๊ฐ ์์ฑ์ด ๋๋ ์๊ฐ ์๋์ ์ผ๋ก 3๊ฐ์ง ์์ ์ ์คํํ๊ฒ ๋๋๋ฐ
1. FIFO๋ฐฉ์์ผ๋ก 'MicroTask'์ 'Event'๋ฅผ ์ค๋น
2. main ํจ์๋ฅผ ์คํ
3. Event loop ์คํ
Event loop๋ 'MicroTask'์ 'Event'๋ฅผ ์ฒ๋ฆฌํ๊ฒ ๋๋ค.
๊ทธ๋ ๋ค๋ฉด 'MicroTask'๋ ๋ฌด์์ผ๊น? ์ผ๋จ ์ด๋ฅผ ์ค๋ช ํ๊ธฐ ์ด์ ์
Future๋ ๋น๋๊ธฐ์ ์์ ์ด๋ผ๋ ๊ฒ์ ์๊ณ ์์ ๊ฒ์ด๋ค.
์ฆ, ๊ทธ๋ ๋ค๋ฉด ๋๊ธฐ์ ์์ ์ด ์คํ์ด ๋๊ณ ๊ทธ ํ์ ๋น๋๊ธฐ์ ์์ ์ด ๋๋๋๊ฒ ๋ง์ ๊ฒ์ด๋ค.
๊ทธ๋ ๋ค๋ฉด ๊ฒฐ๊ตญ ๋๊ธฐ์ ์์ ์ด ์คํ๋๋ ๋์ ๋น๋๊ธฐ์ ์์ ์ ๋ํ ๋๊ธฐ์ด์ ๋ง๋ค์ด์ ๋ณด๊ด์ ํ๊ธฐ ์ํด
'Event'๋ผ๋ ํ์ Future๋ฅผ FIFO ๋ฐฉ์์ผ๋ก ๋ณด๊ดํ๊ฒ ๋๋ค.
์ ๊ทธ๋ฌ๋ฉด, ์ด์ 'MicroTask'์ ๋ํด์ ์ค๋ช ์ ํ์๋ฉด
์์์ ์ค๋ช ํ ๊ฒ ์ฒ๋ผ ๋น๋๊ธฐ์ ์์ ์ด์ธ์ ๋๊ธฐ์ ์์ ์ ๋ํ ๊ฒ๋ค์ 'MicroTask'๋ผ๊ณ ํ๋ค.
์ฆ, Event loop๊ฐ ์คํ๋ ๋ ํ์ ๋ฑ๋ก๋๊ธฐ ์ ์ธ Future๊ฐ ์ด์ธ์ 'MicroTask' ๊ฐ๋ค์ ์ผ๋จ ์ฒ๋ฆฌ ํ๊ฒ ๋๋ค.
๊ทธ ํ ๋์ด์ ๋ด๋ถ์ ์ผ๋ก ์งํํ 'MicroTask'๊ฐ ์๋ค๋ฉด
Event loop๋ ์ธ์ ์ผ๋ก ์ ๋ฌ๋๋ ๊ฐ์ข ์ด๋ฒคํธ์ธ
1. Future
2. Stream
3. Gesture
4. Drawing
5. Reading files
6. Fetching data
7. Button touch
8. etc...
๋ฑ๋ฑ์ ์์ ๋ค์ ์ฒ๋ฆฌํ๊ฒ ๋๋ค.
์ฆ 'MicroTask'๊ฐ ๋๋ ํ์ ์ธ์ ์ธ ์์ ๋ค์ Task๊ฐ Event Queue์ ๋ฑ๋ก์ด ๋๋ค๋ ์๋ฏธ์ด๋ค.
3. ์์ ์ฝ๋๋ฅผ ํตํด Future ์์๋ณด๊ธฐ
์ด์ ๋ ๋์๋ฐฉ์์ ๋ํด์ ๋ฐฐ์ ์ผ๋ ์ฝ๋๋ฅผ ํตํด์ ๋ ์์ธํ๊ฒ ์ดํด๋ฅผ ํด๋ณด๋๋ก ํ์.
๋ช๊ฐ์ ์ฝ๋ ์์ ๋ฅผ ๋ณด๋ฉด์ ๋ฐฉ๊ธ ์ค๋ช ํ ์ด๋ก ์ด ์ด๋ป๊ฒ ์ค์ ๋ก ๋์ํ๋์ง ๋ณต์ตํด๋ณด์.
1-1
void main() {
print('Before the Future');
Future(() => print('Future is complete'));
print('After the Future');
}
์์ ๊ฐ์ ์ฝ๋๊ฐ ์๋ค๊ณ ํ๋ค๋ฉด ๊ฒฐ๊ณผ๊ฐ์ด ์ด๋ป๊ฒ ๋์ฌ์ง ์์ํด๋ณด์.
๋ต์
Before the Future
After the Future
Future is complete
์ด ๋ ๊ฒ์ด๋ค.
์ ์ฒ๋ผ ๊ฒฐ๊ณผ๊ฐ์ด ๋์ค๋ ์ด์ ๋ ์์์๋ ์ค๋ช ํ๋ฏ์ด
๋๊ธฐ์ ์ธ ๋ถ๋ถ์ ๋จผ์ ์คํํ๊ณ Future๊ฐ์ ๋น๋๊ธฐ์ ์ธ ๋ถ๋ถ์ด ๋ค์ด์ค๋ฉด ์ผ๋จ Event Queue์ ๋ฃ๊ณ
๋์ค์ ์ฒ๋ฆฌํ๊ธฐ ๋๋ฌธ์ด๋ค. ๊ทธ๋์ ์ ๊ฒฐ๊ณผ๊ฐ์ด
'Before the Future' -> 'After the Future' -> 'Future is complete' ์์ด ๋๋ค.
4. ์์ ์ฝ๋๋ฅผ ํตํด async, await ์์๋ณด๊ธฐ
Future๋ฅผ ์์๋ดค์ผ๋, ์ด์ ๋ async์ await๋ฅผ ์์๋ณด์.
๋๋ค ์ด๋์ ์ฐ๋ ๊ฒ ์ผ๊น?
๋ฐ ์์๋ฅผ ํ์ธํด๋ณด์.
Future<ProcessedData> createData() {
return _loadFromDisk().then((id){
return _fetchNetworkData(id);
}).then((data){
return ProcessedData(data);
})
}
_loadFromDisk์์ id๊ฐ์ ๋ฐ๊ณ ๊ทธํ _fetchNetworkDate์์ ๋ค์ id๊ฐ์ ๋ฐ๊ณ
๊ทธ ํ ๋ค์ data์ ๊ฐ์ ๋ฐ๊ณ ProcessedDate์ data๊ฐ์ ๋ฃ๋ ์์๋ก ์งํ์ด ๋๋ค.
๋ค๋ง ์ ์ฝ๋๋ ๊ฐ๋ ์ฑ์ด ์ข์๋ณด์ด์ง ์๋๋ค.
๊ทธ๋ ๋ค๋ฉด async์ await๋ฅผ ์ฌ์ฉํ๋ค๋ฉด?
Future<ProcessedData> createDate() async {
final id = await _loadFromDisk();
final data = await _fetchNetworkData(id);
return ProcessedData(data);
}
์ ์ฒ๋ผ ๋๊ฐ์ ๋์์ ํ๋๋ฐ, ์ฝ๋์ ๊ฐ๋ ์ฑ์ ํจ์ฌ ์ข์์ก๋ค.
์ด์ ๋ ์กฐ๊ธ ์ฌํ๋ฒ์ ์ผ๋ก then๊ณผ await๋ฅผ ์ฌ์ฉํด์ ์ฝ๋์ ํ๋ฆ์ด ์ด๋ป๊ฒ ๋์ํ๋์ง ๋ณด์.
void prepareDinner() {
print('Dinner preparation started...');
// ์ฌ๋ฃ๋ฅผ ์ผํํ๋ ๋น๋๊ธฐ ํจ์ ํธ์ถ
Future<String> shopping = shopForIngredients();
// ์ผํ์ด ์๋ฃ๋๋ฉด ์๋ฆฌ ์์
shopping.then((ingredients) {
print('Ingredients bought: $ingredients');
return cookDinner(ingredients); // ์๋ฆฌ ์์
}).then((meal) {
print('Dinner is ready: $meal');
}).catchError((error) {
print('Error: $error');
});
// ์ผํ๊ณผ ์๋ฆฌ๊ฐ ์งํ ์ค์ด์ง๋ง, ์ด ์ฝ๋๋ ๋ฐ๋ก ์คํ๋ฉ๋๋ค.
print('Dinner is being prepared...');
}
Future<String> shopForIngredients() async {
await Future.delayed(Duration(seconds: 3)); // ์ฌ๋ฃ ์ผํ ์๋ฎฌ๋ ์ด์
return 'Fresh tomatoes and basil';
}
Future<String> cookDinner(String ingredients) async {
await Future.delayed(Duration(seconds: 5)); // ์๋ฆฌ ์๋ฎฌ๋ ์ด์
return 'Tomato basil pasta';
}
void main() {
prepareDinner();
print('Main function continues running while dinner is being prepared...');
}
์ ์ฝ๋์ ๊ฒฐ๊ณผ๊ฐ์ ์ด๋ป๊ฒ ๋ ๊น?
์ฐ๋ฆฌ๊ฐ ์ ์ฝ๋๋ฅผ ๋ณผ๋๋ ์ด์ ๋ถํฐ ๋๊ธฐ์ ์ธ ๋ถ๋ถ๊ณผ ๋น๋๊ธฐ์ ์ธ ๋ถ๋ถ์ ๋๋๋ฉด์ ๋ณด๋ฉด ์ดํด๊ฐ ๋ ์ฌ์ธ ๊ฒ ์ด๋ค.
์ผ๋จ ์ฒ์์ผ๋ก๋
'Dinner preparation started...' ์ด ์คํ์ด ๋ ๊ฒ์ด๋ค.
๊ทธ ํ ๋ค์ ๋ผ์ธ์ธ 'Future<String> shopping = shopForIngredients()' ์คํ๋๋๋ฐ
shopForIngredients ํจ์๋ฅผ ๋ณด๋ฉด Future<String>์ ๋ฐํํ๊ณ ์๋ค.
Future<String> shopForIngredients() async {
await Future.delayed(Duration(seconds: 3)); // ์ฌ๋ฃ ์ผํ ์๋ฎฌ๋ ์ด์
return 'Fresh tomatoes and basil';
}
์ฌ๊ธฐ์๋ 3์ด๋ฅผ ๊ธฐ๋ค๋ฆฐ ํ์ String๊ฐ์ ๋ฐํํ๋ค.
ํ์ง๋ง ์์ ๊ณต๋ถํ๋ฏ์ด,
'Future shopping = shopForIngredients()' ์์ await๊ฐ ์์ผ๋ฏ๋ก ๊ธฐ๋ค๋ฆฌ์ง ์๊ณ ์ผ๋จ Future<String>๊ฐ์ ๋ฐํํ๋ค.
๊ทธ๋ฌ๋ฏ๋ก shopping๊ฐ์๋ Future<String>๊ฐ์ด ๋ค์ด ๊ฐ ๊ฒ์ด๋ค. (ํ์ธํด๋ณด์ง๋ ์์์ง๋ง ์ด๋ก ์ ๊ทธ๋ด ๊ฒ์ด๋ค.)
์ด์ ๊ทธ ํ then ํจ์๋ฅผ ๋ง๋๊ฒ ๋๋๋ฐ ์ด๊ฒ๋ ๋น๋๊ธฐ์ ์ธ ๋ถ๋ถ์ด๋ผ ์ผ๋จ event queue์ ๋ฃ๊ณ ๋์ค์ ์ฒ๋ฆฌํ ๊ฒ์ด๋ค.
shopping.then((ingredients) {
print('Ingredients bought: $ingredients');
return cookDinner(ingredients); // ์๋ฆฌ ์์
}).then((meal) {
print('Dinner is ready: $meal');
}).catchError((error) {
print('Error: $error');
});
์ด์ ๋ค์์ผ๋ก 'Dinner is being prepared...' ๊ฐ ์ถ๋ ฅ์ด ๋๊ณ
Main์ ์๋ 'Main function continues running while dinner is being prepared...' ๊ฐ ์ถ๋ ฅ์ด ๋๋ค.
์ด์ ์ฒ๋ฆฌ๊ฐ ์๋ฃ๋์ง ๋ชปํ ๋น๋๊ธฐ์ ์ธ ๋ถ๋ถ์ผ๋ก ๋ค์ ๋์ด๊ฐ์
shopping.then((ingredients) {
print('Ingredients bought: $ingredients');
return cookDinner(ingredients); // ์๋ฆฌ ์์
}).then((meal) {
print('Dinner is ready: $meal');
}).catchError((error) {
print('Error: $error');
});
ingredients์ด๋ผ๋ ๊ฐ์ 3์ด๋ฅผ ๋๊ธฐ ํ ๊ฐ์ด ํ์ด๋์ค๊ฒ ๋๊ณ ,
'Ingredients bought: Fresh tomatoes and basil' ๊ฐ ์ถ๋ ฅ
Future<String> shopForIngredients() async {
await Future.delayed(Duration(seconds: 3)); // ์ฌ๋ฃ ์ผํ ์๋ฎฌ๋ ์ด์
return 'Fresh tomatoes and basil';
}
Future<String> cookDinner(String ingredients) async {
await Future.delayed(Duration(seconds: 5)); // ์๋ฆฌ ์๋ฎฌ๋ ์ด์
return 'Tomato basil pasta';
}
5์ด ํ์ 'Dinner is ready: Tomato basil pasta' ๊ฐ ์ถ๋ ฅ๋๊ณ ์ข ๋ฃ ๋๋ค.
5. ์ถ๊ฐ ์์
Future<void> printOrderMessage() async {
print('Awaiting user order...');
var order = await fetchUserOrder();
print('Your order is: $order');
}
Future<String> fetchUserOrder() {
// Imagine that this function is more complex and slow.
return Future.delayed(const Duration(seconds: 4), () => 'Large Latte');
}
void main() async {
countSeconds(4);
await printOrderMessage();
}
// You can ignore this function - it's here to visualize delay time in this example.
void countSeconds(int s) {
for (var i = 1; i <= s; i++) {
Future.delayed(Duration(seconds: i), () => print(i));
}
}
์ ์ฝ๋์ ๊ฒฐ๊ณผ๊ฐ์ ์ด๋ป๊ฒ ๋ ๊น?
๋ด๊ฐ ์ฒ์ ์์ํ ๊ฒฐ๊ณผ๊ฐ์ ์๋์ ๊ฐ๋ค.
Awaiting user order...
Your order is: Large Latte
1
2
3
4
ํ์ง๋ง ์ค์ ์ถ๋ ฅ๊ฒฐ๊ณผ๊ฐ์
Awaiting user order...
1
2
3
4
Your order is: Large Latte
์์ ๊ฐ์๋ค.
์ ๊ทธ๋ฐ๊ฒ์ผ๊น? ํ๋ฒ ์ฝ๋์
var order = await fetchUserOrder();
print('Awaiting user order...');
์ ๋์ค์ ์์๋ฅผ ๋ณ๊ฒฝํด๋ณด์๋ค.
1
2
3
4
Awaiting user order...
Your order is: Large Latte
๊ทธ๋ฌ๋๋ ๊ฒฐ๊ณผ๊ฐ์ด ์ด๋ ๊ฒ ๋์๋ค.
์ฆ, ๋ด๊ฐ ์ดํดํ๊ฒ ๋ง๋ค๋ฉด
await๋ฅผ ๋ง๋๋ฉด ๊ทธ ํจ์์ ์คํ์ ์ ์ ๋ฉ์ถ๊ณ Event Queue์ ์๋ ๊ฐ๋ค์ FIFO์ผ๋ก ์ฒ๋ฆฌํ๋ค์
๋๋ฒ์งธ ์์์ธ
var order = await fetchUserOrder();
print('Awaiting user order...');
print('Your order is: $order');
๋ฅผ ์ฒ๋ฆฌํ๋ ๊ฒ ๊ฐ๋ค.
๋ง๋ฌด๋ฆฌ ์ดํ
์ญ์ ํ๋ฌํฐ๋ ๋ฐฐ์ธ ์๋ก ์ฌ๋ฐ๋ค. ์์ด ๊ณต๋ถ๋ฅผ ์ด์ฌํ ํด์ ๊ณต์๋ฌธ์๋ฅผ ์์ด๋ฏผ ์ฒ๋ผ ์ฝ์ด๋ณด์!