2020/6/7 dart:async – asynchronous programming

dart:async – asynchronous programming

非同期処理のプログラミングではよくコールバック関数を使って実装しますが、Dart言語では代わりに、FutureクラスとStreamクラスのオブジェクトを使用します。Futureクラスは未来のある時点で結果が提供される「約束」のようなものです。Streamクラスは複数のイベントのような、複数の値を得る方法です。


dart:asyncライブラリはwebアプリとコマンドラインアプリの両方で機能します。ライブラリを使用するときは、dart:asyncライブラリをインポートします。

import 'dart:async';

Version note

Dart2.1からFutureクラスとStreamクラスを使用する際dart:asyncライブラリをインポートする必要はなくなりました。



Future

Futureオブジェクトは、主に非同期なメソッドの返り値として、Dartライブラリの中によく登場します。future(Futureクラスのインスタンス)がcomplete(完了)すると、結果の値を使用することができます。

awaitを使おう(Using await)

Future APIを直接使おうとする前に、awaitを代わりに使用することを考えてください。その方が理解しやすいコードを書くことができます。

下記の関数を考えてみます。runUsingFuture関数は、三つの非同期関数を実行するためにFutureクラスのthen()メソッドを使っています。次の非同期関数を実行する前に、その前の非同期関数の結果を待ちます。

sample1-1

runUsingFuture() {
  // ...
  findEntryPoint().then((entryPoint) {
    return runExecutable(entryPoint, args);
  }).then((exitCode){flushThenExit(exitCode)});
}

 

具体的に、findEntryPoint()関数がcomplete(完了)した時に、その結果を引数entryPointで受け取って、

(entryPoint) {
    return runExecutable(entryPoint, args);
  }

を実行する。runExcutable関数は非同期関数。thenメソッドはFutureインスタンスを返す。その返ってきたfutureがcompleteした時、その結果を引数としてflushThenExit関数に渡して実行される。


sample1-1をawaitを使って書くとsample1-2のようになります。

sample1-2

runUsingAsyncAwait() async {
  // ...
  var entryPoint = await findEntryPoint();
  var exitCode = await runExecutable(entryPoint, args);
  await flushThenExit(exitCode);
}

async関数はFutureからの例外をキャッチすることができます。例としては、

sample1-3

var entryPoint = await findEntryPoint();
try {
  var exitCode = await runExecutable(entryPoint, args);
  await flushThenExit(exitCode);
} catch (e) {
  // エラー処理コード...
}

⚠️Important:Async関数はFutureインスタンスを返します。あなたの関数がfutureを返したくない場合は別の方法を考えましょう。


基本的な使い方(Basic usage)

then()メソッドは、futureがcomplete(完了)した時に実行するコードを設定する時に使います。例えば、HTTPリクエストは時間がかかることが予想される処理ですので、HttpRequest.getString()メソッドはFutureクラスのインスタンスを返します。then()メソッドを使うと、Futureインスタンスがcompleteした時に実行する処理を指定できます。そしてその中で、受け取ったFutureの結果の値を利用することができます。

sample1-4

HttpRequest.getString(url).then((String result) {
  print(result);
});

sample1-4では、Httpリクエストにより文字列を得られた時(completeした時)に、その得られた文字列を表示するコードが実行されます。

catchError()メソッドを使うと、Futureインスタンスがthrowした(投げた)エラーや例外を処理することができます。

sample1-5

HttpRequest.getString(url).then((String result) {
  print(result);
}).catchError((e) {
  // Handle or ignore the error.
});

then().catchError()のパターンは、try-catch文の非同期バージョンです。


Chaining multiple asynchronous methods

then()メソッドはFutureインスタンスを返します。ですので、複数の非同期関数をあるべき順番で実行する便利な方法が存在します。

then()で登録されたコールバック関数がFutureを返す場合、then()メソッドもそのFutureを返します。

then()で登録されたコールバック関数が別の型の値を返す場合、then()はその値と共に完了する新しいFutureを生成します。

sample1-6

Future result = costlyQuery(url);
result
    .then((value) => expensiveWork(value))
    .then((_) => lengthyComputation())
    .then((_) => print('Done!'))
    .catchError((exception) {
  /* Handle exception... */
});

sample1-6では、以下の順番で関数が実行されます。

  1. costlyQuery()
  2. expensiveWork()
  3. lengthyComputation()

awaitを用いて記述するとsample1-7のようになります。

sample1-7

try {
  final value = await costlyQuery(url);
  await expensiveWork(value);
  await lengthyComputation();
  print('Done!');
} catch (e) {
  /* Handle exception... */
}

Waiting for multiple futures

時には、複数の非同期関数を実行し、次の処理にいく前に全ての非同期関数のcompleteを待つ必要がある場合があるかもしれません。そういう時は、staticメソッドであるFuture.wait()メソッドを使います。(sample1-8)

sample1-8

Future deleteLotsOfFiles() async =>  ...
Future copyLotsOfFiles() async =>  ...
Future checksumLotsOfOtherFiles() async =>  ...

await Future.wait([
  deleteLotsOfFiles(),
  copyLotsOfFiles(),
  checksumLotsOfOtherFiles(),
]);
print('Done with all the long steps!');

 

 

 

 

 

 

参考

https://dart.dev/guides/libraries/library-tour

コメントを残す

メールアドレスが公開されることはありません。