티스토리 뷰

다트 공식 문서 번역

다트] 비동기 지원

철철박사 2024. 8. 12. 18:24
반응형

다트 라이브러리는 Future 또는 Stream 객체를 반환하는 함수들이 많이 있다. 이러한 함수들은 비동기적이다. 즉, 입출력과 같이 시간이 오래 걸릴 수 있는 작업을 요청한 후에도 작업이 완료될 때까지 기다리지 않고 반환되어, 다른 작업을 할 수 있게 된다.

 

async와 await 키워드는 동기 코드를 비동기 코드와 유사하게 작성할 수 있도록 도와준다.

 

 

 

Future 다루기

완료된 Futurue의 결과가 필요할 때는 두 가지 방법이 있다.

  • async와 await를 사용하기
  • then()으로 처리하기

async와 await 를 사용하는 코드는 비동기적이지만, 동기 코드와 매우 유사하게 보인다. 예를 들어, 비동기 함수의 결과를 기다리기 위해 await를 사용하는 코드는 다음과 같다.

await lookUpVersion();

 

await를 사용하려면, 코드는 async로 표시된 함수 내에 있어야 한다.

Future<void> checkVersion() async {
  var version = await lookUpVersion();
  // 버전과 관련된 작업 수행
}

 

async 함수는 첫 번째 await 표현식을 만날 때까지 실행되며, 이후 Future 객체를 반환하고 await 표현식이 완료되면 실행을 재개한다.

 

await를 사용하는 코드에서 오류 처리와 정리를 위해 try, catch, finally를 사용할 수 있다.

try {
  version = await lookUpVersion();
} catch (e) {
  // 버전을 조회할 수 없는 경우 처리
}

 

하나의 async 함수 내에서 여러 번 await를 사용할 수 있다. 예를 들어, 다음 코드는 세 번의 비동기 함수 결과를 기다린다.

var entrypoint = await findEntryPoint();
var exitCode = await runExecutable(entrypoint, args);
await flushThenExit(exitCode);

 

await 사용 시 컴파일 타임 오류가 발생하면, await 가 async 함수 내에 있는지 확인하자. 예를 들어, 애플리케이션의 main() 함수에서 await를 사용하려면, main() 함수의 바디를 async로 표시해야 한다.

void main() async {
  checkVersion();
  print('In main: version is ${await lookUpVersion()}');
}

 

위의 예제는 main()는 checkVersion()의 결과를 기다리지 않고 사용하고 있다. 이러한 방식은 실행을 마쳤다고 가정하는 코드에서 문제가 발생할 수 있다. 이 문제를 피하려면 unawaited_futures 린터 규칙을 사용하자.

 

// 추가 설명이 필요함

 

 

 

async 함수 선언

async 함수는 본문이 async 수정자로 표시된 함수이다. 함수에 async 키워드를 추가하면 해당 함수는 Future를 반환한다.

 

예를 들어, 다음은 String을 반환하는 동기 함수이다.

String lookUpVersion() => '1.0.0';

 

만약 실행 시간이 많이 소요된다면 async를 사용하여 비동기 함수로 변경하고 반환값은 Future가 된다.

Future<String> lookUpVersion() async => '1.0.0';

 

비동기 함수는 바디에서 Future로 반환하지 않아도 된다. 필요한 경우 다트가 Future 객체를 생성한다. 

 

값을 반환하지 않는 비동기 함수는 반환 타입을 Future<void>로 만들자.

 

 

 

Stream 다루기

Stream에서 값을 가져와야 할 때는 두 가지 방법이 있다.

  • await-for 루프를 사용한다.
  • listen()을 사용한다.

참고로 await-for 루프를 사용하기 전에, 이 방법이 코드를 더 명확하게 만드는지, 그리고 스트림의 모든 결과를 기다리는 것이 맞는지 확인하자. 예를 들어, UI 이벤트 리스너에는 await-for를 사용하는 것이 일반적으로 적합하지 않다. UI 프레임워크는 끝없이 이벤트 스트림을 전송하기 때문이다.

 

await-for 루프는 다음과 같은 형식을 가진다.

await for (varOrType identifier in expression) {
  // 스트림이 값을 방출할 때마다 실행됩니다.
}

 

expression의 값은 Stream 타입이어야 한다. 실행 과정은 다음과 같다.

  1. 스트림이 값을 방출할 때까지 기다린다.
  2. 방출된 값을 사용하여 for 루프의 본문을 실행한다.
  3. 스트림이 종료될 때까지 1과 2를 반복한다.

스트림 청취를 중지하려면, for 루프를 중단하고 스트림 구독을 취소하는 break 또는 return 문을 사용할 수 있다.

 

await-for 루프 구현 시 컴파일 타임 오류가 발생하면, await-for이 async 함수 내에 있는지 확인하자. 예를 들어, 애플리케이션의 main()에서 await-for 루프를 사용하려면 main() 함수의 본문을 async로 표시해야 한다.

void main() async {
  // ...
  await for (final request in requestServer) {
    handleRequest(request);
  }
  // ...
}

 

반응형
댓글
공지사항