본문 바로가기
프로그래밍/Flutter

[Flutter] Dart 비동기 처리, Future 사용하기

by 신나요 2022. 5. 7.

Dart의 비동기 처리 1탄으로 Future 사용법에 대해 알아보도록 하겠습니다. 동기식 코드를 살펴보고 Future를 이용해서 동기식을 비동기 처리로 바꿔보겠습니다.

 

이번 포스트는 다음 내용을 다루고 있습니다.

  • 동기식 코드 살펴보기
  • Future 란?
  • Future 사용해 비동기 처리로 바꿔보기
  • Future의 상태
  • 반환 값이 있는 Future

동기식 코드 살펴보기

아래 코드를 보고 호출 순서를 생각해보세요.

main 메소드에서 비동기 처리로 바꿔야 할 세 개의 메소드를 호출하고 있습니다. mockFileIO, mockHttpRequest, mockDBQuery는 실제 처리를 하는 메소드는 아니지만 실제로 파일 입출력, http리퀘스트, 디비 쿼리를 수행하는 처리 시간이 오래 걸리는 메서드라고 정의하겠습니다.

현재 모든 기능은 동기식입니다. 각 함수의 호출은 첫번째 함수 호출을 제외하고 이전 함수가 완료된 후에만 실행할 수 있습니다. 따라서 mockHttpRequest는 mockFileIO가 완료된 후에만 실행할 수 있고 mockDBQuery는 mockHttpRequest가 완료된 후에만 실행할 수 있습니다.

VSCode에서 예제를 실행해 보겠습니다.

예상대로 차례대로 실행되었습니다. 하지만 작업이 순간적으로 끝나기 때문에 시간이 오래 걸리는 동기 처리 작업이 앱에 미치는 영향을 보기는 힘든 것 같습니다.

 

Dart IO패키지를 이용해서 의도적으로 처리 시간이 오래 걸리도록 만들어 보겠습니다.

mockHttpRequest메소드에서 Sleep으로 8초간 정지를 하고 있습니다. 이 상태에서 실행해보면 동기 작업이 앱에 미치는 영향이 분명히 드러납니다.

Http 리퀘스트가 시작되고 나서 8초간 프로그램이 멈춰 버립니다. 실제로 웹 통신을 한다고 생각하면 리퀘스트를 보내고 리스폰스가 올 때까지 대기하게 될 것입니다. 이러한 처리는 사용자 경험을 저하시키고 앱이 다운되었다고 생각하게 할 수도 있습니다. 이를 방지하는 방법은 HTTP 요청을 비동기적으로 실행하는 것입니다. 이제 비동기 처리를 위해 Future를 알아볼 시간이 되었습니다.


Future 란?

다트와 플러터의 비동기 작업은 Future로 표현됩니다. Future는 비동기 처리의 상태 혹은 값을 나타내는데, 비동기 처리를 수행하는 함수는 Dart언어에 포함된 Future클래스의 인스턴스를 반환하게 됩니다. Future는 제네릭 클래스이고 제네릭 타입은 Future의 반환 값과 동일합니다. Future의 값은 Future가 나타내는 연산의 반환 값이 됩니다. 반환 값이 없다면 Future는 void으로 처리할 수 있습니다.

 

Future 사용해 비동기 처리로 바꿔보기

VSCode로 돌아가서 sleep 호출을 제거하고 Future.delayed에 대한 호출을 삽입하겠습니다.

Future.delayed 함수는 지속시간 동안 기다린 후 전달한 다른 함수를 실행합니다. 하지만 기다리는 동안 프로그램을 블록 하지 않습니다. 위 예의 경우 비동기 작업은 Future.delayed에 전달된 함수가 됩니다. 전달된 함수가 값을 반환하지 않으므로 Future의 유형은 void가 됩니다. 따라서 mockHttpRequest의 리턴 타입도 Future<void>로 바꿔 주니다.

 

이제 다시 결과를 출력해 보겠습니다.

출력 결과를 보면 "HTTP리퀘스트: 시작" 까지 출력되고 mockDBQuery 메소드가 호출되고 출력되는 걸 볼 수 있습니다. 결과를 해석해보면, mockHttpRequest 함수가 시작된 다음 Future를 반환하게 되고 Future가 완료되기를 기다리면서 다음 처리인 mockDBQuery 함수를 호출해 출력을 하게 됩니다. 8초 후에 Future가 완료되고 네트워크 호출 결과를 콘솔에 출력하게 됩니다.

mockHTTPRequest 함수는 비동기식으로 수행할 작업을 나타내는 Future를 반환했습니다. 따라서 mockDBQuery 함수는 비동기 처리가 완료될 때까지 기다릴 필요가 없게 됩니다.

 

Future의 상태

Dart는 Future가 언제 완료(complete)되었는지 어떻게 알 수 있을까요? Future에는 두 가지 상태가 있습니다. Future가 비동기 작업이 완료되기를 기다리는 동안에 상태는 "Uncompleted"상태가 됩니다. 비동기 작업이 완료되면 "Complete"으로 상태가 변경됩니다. 완료(completed)된 상태의 Future는 성공한 비동기 처리의 반환 값을 포함할 수 있습니다. 완료된 작업 값은 반환되면 Future의 제네릭 타입과 동일한 타입이 되거나 값이 없을 경우 void가 됩니다. 성공적으로 완료되지 않은 Future는 에러를 던지게 되고 Future에서 에러 처리를 해줘야 합니다.

 

반환 값이 있는 Future

Future의 반환 값이 있게 다시 수정해 보도록 하겠습니다.

Future에 전달하는 함수를 변경하여 문자열을 반환하도록 수정하였습니다. 문자열을 반환하게 되었으니 mockHttpRequest의 리턴 타입도 Future<String>으로 바꿔주었습니다. 이제 main함수를 살펴보면 mockHttpRequest에서 반환되는 Future를 response에 할당해주고 Future에서 then 메서드를 호출하여 Future가 완료될 때 호출될 함수를 설정하고 있습니다. 함수의 매개변수 s에 Future에서 리턴되는 문자열이 할당되므로 그 값을 이용해 메시지를 인쇄하였습니다.

 

앱을 실행하면 아래와 같이 출력됩니다.

8초 후에 Future가 완료되고 비동기 작업에서 반환된 문자열이 then 메서드의 함수에 전달됩니다. 원하는 대로 비동기 처리가 이뤄지는 걸 확인할 수 있습니다.

 

Future로 코드를 구성하는 방법은 비동기 작업에 필요한 모든 코드를 순서대로 배치하는 것보다 훨씬 관리하기 쉽습니다. 또한 비동기 처리의 범위가 작을수록 애플리케이션에서 더 쉽게 재사용할 수 있게 됩니다.


여기까지 수고하셨습니다. 다음 포스트에서는 async 및 awit 키워드에 대해 알아보도록 하겠습니다.

 

 

댓글