Flutter

[Flutter] Future async await

문앵 2022. 7. 26. 18:03

1. Future

 

Future 클래스는 미래에 뭔가 구체적인 결과물로 나타나서 실제적인 객체로 반환된다는 약속.

 

 

자바 스크립트의 Promise 클래스와 같은 의미라고 생각하면 된당

 

 

 

 

 

 

 

Future 특징 :

원하는 데이터형을 지정해줄 수 있음 Future<String> 어쩌구(){}

 

주로 Future.delay(dutarion,뭔가함수()) 이런식으로 delay매소드와 함께 많이 씀.

 

 

2. 비동기 처리하기 (sleep매소드 vs Future.delay())

비동기적인 처리를 원할 때 Future.delay() 를 이용할 수 있다.

 

예를 들어 sleep 함수를 사용해서 실행을 늦추는 방법 vs Future.delay를 사용해서 실행을 늦추는 방법을 비교를 통해

비동기 원리를 아라보자. 

먼저 기본적인 코드 뼈대는 이상태에서 진행을 했다

import "dart:io";

void main(){
  startStudying();
}

void startStudying(){
  getStart();
  accessData();
  fetchData();
}

void getStart(){
  print("start!");
}

void accessData(){
  print("get data!");
}

void fetchData(){
  print("finally!");
}

=> 

 

 

 

 

 

 

① sleep

 

accessData() 함수를 아래처럼 sleep매소드를 이용해 작성하면 

void accessData(){
  Duration time = Duration(seconds: 3); // Duration클래스로 객체 생성
  sleep(time); // sleep함수 => 함수 들어가보면 Duration 타입의 변수를 받고 있음. 저 듀레이션만큼 멈춤
  print("get data!");
}

 

start가 먼저 찍히고 3초 뒤 , get data! 와 finally! 가 함께 (엄밀히 말하면 순서가 있지만) 찍히는것을 알수있다.

즉, main() 함수와 startStudying() 함수는 동기적으로 순차적으로 실행 되었다.

 

- accessData() 함수가 모두 실행 되고나서(3초 딜레이까지 모두),
그 다음인 fetchData()함수가 실행 된것이다.

 

 

 

 

그럼 Future 클래스를 이용해서 delay 메소드를 사용해본다.

 

② Future.delay()

void accessData(){
  Duration time = Duration(seconds: 3); // Duration클래스로 객체 생성
  // sleep(time); // sleep함수 => 함수 들어가보면 Duration 타입의 변수를 받고 있음. 저 듀레이션만큼 멈춤
  Future.delayed(time,(){
    print("get data!");
  });
}

간단하다. Future.delayed() 안에는 duration 객체와, 실행할 함수가 인자로 들어간다.

 

근데 신기하게 이렇게 써주면 실행결과는 , 

왼쪽 사진 - (3초뒤)-> 오른쪽 사진 처럼 됐다.

 

즉, 두번째 실행 함수가 3초 연기되는 동안 세번째 함수가 먼저 실행된 것이다. 

Future.delayed() 함수를 만나면 멈추고 그 다음 코드를 먼저 실행 하라고 한다.

 

 

=> 결론 : Future 클래스는 비동기적인 동작을 하고싶을때 사용할 수 있다.

 

 

 

2. async await

근데 얘도 마찬가지다. 마찬가지로 비동기 동작을 수행하고싶을때 사용하면 된다.

위 코드에서 내가 두번째 함수에서 변수를 만들어서 세번째 함수에서 인자로 받아서 사용할 수 있도록 코드를 수정해보자.

 

1. 먼저 두번째 함수에서는 임의의 String 변수 account 를 만들어주고 이 값을 리턴해주도록 한다,

2. 그 다음 세번째 함수를 실행시킬 때 두번째 함수의 결과값으로 받은 account 변수를 인자로 갖도록 하고,

3. 마지막 세번째 함수내부에서는 이 인자값을 받아서 사용해보도록 코드를 수정한다.

 

1 > accessData()

String? accessData(){ // String 반환값을 가지므로 void 타입 => String 타입으로 바꿔준다.
	String? account; // 변수 선언
	Duration time = Duration(seconds : 3); //Future.delayed() 매소드에 쓸 duration 객체 생성
    Future.delayed(time,(){ // 3초 멈춤. but 비동기적으로 이 다음 코드는 실행
    	account = "200만원";
        print("get $account data!")
    });
    return account; // account 변수 반환. 
}

이 코드를 살펴보면 account 변수를 반환해주는것은 원래 , account 에 "200만원"을 할당해준 이후에 일어나야 하는 것인데.

함수 내부에서 Future.delayed를 만나면서 account = "200 만원" 보다 return account가 먼저 실행되어버린다. 

 

이것은 나중에 변수를 사용해서 표출했을때 문제가 된닷.

 

 

2 > startStudying()

void startStudying(){
  getStart();
  String? account2 = accessData(); // accessData() 반환 결과를 account라는 변수에 담는다.
  // 이 부분은 return 값이 있는 함수에 한해서만 가능하다
  fetchData(account2); // account 변수를 인자로 받아서 fetchData(account)함수를 실행
}

account 변수로 accessData 값 받아서 fetchData 인자로 넘겨주기

 

 

 

3 > fetchData()

void fetchData(String? account){
	print("finally fetch $account !");
}

fetchData() 인자로 받아서 print에 표출해주기

 

=> 결과는 ?

왼쪽 - (3초후)-> 오른쪽사진이 나왔다.

 

즉 세번째 함수에서 찍은 account가 null로 반환된 것!

 

why? 

위에서도 썼다시피 문제는 두번째 함수이다.

두번째 함수에서 Future.delayed()를 만나면서

account 변수에 값이 할당되기도 전에 account를 return해 버렸고, 그 반환값을 첫번째 함수에서 고대로 새로 변수에 담아서 세번째 함수 인자로 전달해줬기 때문에 세번째 함수가 실행되면서 null 값을 읽어와 버렸다.

 

그럼 만약 이때 이 account에 할당 된 "200만원"을 고대로 세번째 함수에서 가져다가 쓰고싶다면 어떻게 할까?

account 값이 할당 된 이후에 account를 반환하면? 그걸로 끝이다.

 

이럴때 쓸 수 있는게 바로 async await다.

 

먼저 두번째 함수 (accessData())에서 3초간 딜레이 후 account에 값이 할당 되므로,

미래에 특정 값이 행기는 Future클래스 특성을 가지고 있다.

따라서 클래스를 Future로 바꿔준다. (이때 타입은 String타입을 반환하므로 <String?>)

Future<String?> accessData(){
	String? account;
    Duration time = Duration(seconds : 3);
    Future.delayed(time,(){
    	account= "200만원";
    });
    return account;
}

그리고 이상태에서 ,

async 제어자를 사용해주면 된다. -> async는 반드시 중괄호 앞에 붙인다.

그리고 기다리고싶은 값 앞에 await을 붙여주면 된다.

Future<String?> accessData() async{
	String? account;
    Duration time = Duration(seconds : 3);
    await Future.delayed(time,(){
    	account= "200만원";
    });
    return account;
}

=> " Future.delayed() 값 나올때까지 기다릴거야 "

 

마찬 가지로 첫번째 함수에서도 똑같은 작업을 해준다.

void StartStudying() async{
	getStart();
  	String? account2 = await accessData();
  	fetchData(account2);
}

=> " accessData() 실행 완료될때까지 기다릴거야 "

 

결과는 ?

 

 

딜레이 시간과 데이터 모두 의도대로 적용 되어서 잘 나온다~

 

 

 

 

 

 

async await 개념이랑 Future.delayed , sleep 개념이 헷갈렸는데 공부하면서 정리가 되었다 ^ㅡ^

 

공부 자료 :

https://www.youtube.com/watch?v=oFXV4qSXNVs 

 

반응형