Dart-02: Language Tour
Dart-02-01   Important concepts
Dart-02-02   Keywords
Dart-02-03   Variables
Dart-02-04   Built-in types
Dart-02-05   Functions
Dart-02-06   Operators
Dart-02-07   Control flow statements
Dart-02-08   Exceptions
Dart-02-09   Classes
Dart-02-10   Generics
Dart-02-11   Libraries and visibility
Dart-02-12   Asynchrony support
Dart-02-13   Generators
Dart-02-14   Callable classes
Dart-02-15   Isolates
Dart-02-16   Typedefs
Dart-02-17   Metadata
Dart-02-18   Comments

Asynchrony support

Dart - Asynchrony support

Dart library는 Future 또는 Stream 객체를 반환하는 함수로 가득 차 있다. 이러한 함수는 asynchronous(비동기식)이다: 시간이 많이 소요될 수 있는 작업(such as I/O)을 설정한 후, 해당 작업이 완료될 때까지 기다리지 않고 반환된다.

asyncawait keyword는 비동기 programming을 지원하므로, 동기 code와 유사한 비동기 code를 작성할 수 있다.

0. Example

const oneSecond = Duration(seconds: 1);
// ...
Future<void> printWithDelay(String message) async {
  await Future.delayed(oneSecond);
  print(message);
}
Future<void> printWithDelay(String message) {
  return Future.delayed(oneSecond).then((_) {
    print(message);
  });
}
Future<void> createDescriptions(Iterable<String> objects) async {
  for (final object in objects) {
    try {
      var file = File('$object.txt');
      if (await file.exists()) {
        var modified = await file.lastModified);
        print('File for $object already exists. It was modified on $modified.');
        continue;
      }
      await file.create();
      await file.writeAsString('Start describing $object in this file.');
    } on IOException catch (e) {
      print('Cannot create description for $object: $e');
    }
  }
}
Stream<String> report(Spacecraft craft, Iterable<String> objects) async* {
  for (final object in objects) {
    await Future.delayed(oneSecond);
    yield '${craft.name} flies by $object';
  }
}

1. Handling Futures

completed Future의 결과가 필요한 경우, 두 가지 option이 있다.

  • asyncawait를 사용한다.
  • Future API를 사용한다.

asyncawait를 사용하는 code는 비동기식이지만, 동기식 code와 많이 유사해 보인다. 예를 들어, 비동기 함수의 결과를 기다리는 데 await를 사용하는 몇 가지 code가 있다:

await lookUpVersion();

await를 사용하려면, code가 async라고 표시된 함수인 async 함수에 있어야 한다.

Future<void> checkVersion() async {
  var version = await lookUpVersion();
  // Do something with version
}

async 함수는 시간이 많이 걸리는 작업을 수행할 수 있지만, 해당 작업을 기다리지는 않는다. 대신, async 함수는 첫 번째 await expression을 만날 때까지만 실행된다. 그런 다음 await expression이 complete된 후에만 실행을 재개하는 Future 객체를 반환한다.

await를 사용하는 code에서 error를 정리 및 처리하려면, try, catch, finally를 사용한다:

try {
  version = await lookUpVersion();
} catch (e) {
  // React to inability to look up the version
}

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

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

await expression에서, expression의 값은 일반적으로 Future이다. 그렇지 않은 경우, 값은 자동으로 Future에 wrapp 된다. 이 Future 객체는 객체를 return 하겠다는 약속을 나타낸다. await expression의 값은 return된 객체이다. await expression은 해당 객체를 사용할 수 있을 때까지 실행을 일시 중지한다.

await를 사용할 때 compile-time error가 발생하면, async 함수 안에 await가 있는지 확인한다. 예를 들어, app의 main() 함수에 await를 사용하기 위해서는, main()의 본문에 async를 표시해야 한다:

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

앞의 예제에서는 결과를 기다리지 않고 async 함수 (checkVersion())을 사용한다. code에서 함수 실행이 완료되었다고 가정하면 문제가 발생할 수 있다. 문제를 방지하려면, unawaited_futures linter rule을 사용한다.

2. Declaring async functions

async 함수는 본문이 async modifier로 표시된 함수이다.

함수에 async keyword를 추가하면, 그 함수는 Future를 return 한다. 예를 들어, String을 return하는 다음 동기 함수를 생각해볼 수 있다:

String lookUpVersion() => '1.0.0';

예를 들어, future 구현에 시간이 많이 걸리기 때문에, async 함수로 변경하면, return 값은 Future이다:

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

함수의 본문은 Future API를 사용할 필요가 없다. Dart는 필요한 경우 Future 객체를 생성한다. 함수가 유용한 값을 return 하지 않으면, return type을 Future<void>로 지정한다.

3. Handling Streams

Stream에서 값을 가져와야 하는 경우, 두 가지 option이 있다.

  • async와 asynchronous for loop(await for)을 사용한다.
  • Stream API를 사용한다.

await for를 사용하기 전에, code를 더 명확하게 만들고 Stream의 모든 결과를 정말로 기다리고 싶은지 확인해야 한다. 예를 들어, UI framework는 event의 끝없는 stream을 보내기 때문에, 일반적으로 UI event listener에 await for를 사용해서는 안 된다.

비동기 loop의 형식은 다음과 같다:

await for (varOrType identifier in expression) {
  // Executes each time the stream emits a value.
}

expression의 값은 Stream type이어야 한다. 실행은 다음과 같이 진행된다:

  1. stream이 값을 방출할 때까지 기다린다.
  2. 변수가 방출된 값으로 설정된 상태에서, for loop의 본문을 실행한다.
  3. stream이 닫힐 때까지 1과 2를 반복한다.

stream listening을 중지하려면, for loop에서 벗어나 stream을 unsubscribe하는 breakreturn문을 사용할 수 있다.

asynchronous for loop를 구현할 때 compile-time error가 발생하면, async 함수 안에 await for이 있는지 확인한다. 예를 들어, app의 main() 함수에서 asynchronous for loop를 사용하려면, main()의 본문에 async를 표시해야 한다:

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

태그:

카테고리:

업데이트:

댓글남기기