🐻‍❄️

Future で非同期処理をやる方法

2021/11/13に公開

Future とは

  • Future は非同期処理を実行するために使われる。
  • Future では非同期的に値を取得する機能をサポートしている。
  • 詳しくは以下の動画見るとわかりやすい

Dart Futures - Flutter in Focus

Future で同期/非同期処理を実行する

Future は実行したい処理を async ブロックで囲むことで生成できる。

Future<int> createFuture() async {
  return 0;
}

生成した Future の then を呼び出すことで非同期的に処理が実行される。

void main() {
  var future = createFuture();
  future.then((value) => print("get ${value}"));
}
get 0

Future で例外処理を実行する

then の onError を利用した例外処理

Future では then の onError で例外に対応できる仕組みになっている。以下のように onError を記述すると Future の非同期処理中に発生した例外を処理できる。

void main() {
  var future = createErrorFuture();
  future.then((value) => print("get ${value}"), onError: (e) => print("${e}"));
}

Future<int> createErrorFuture() async {
  throw Exception("happened error on future!");
}
Exception: happened error on future!

catchError を利用した例外処理

Future の catchError でも例外に対応できる仕組みになっている。以下のように catchError を記述すると Future の非同期処理中に発生した例外を処理できる。

void main() {
  var future = createErrorFuture();
  future.then((value) => print("get ${value}")).catchError((e) => print("${e}"));
}

Future<int> createErrorFuture() async {
  throw Exception("happened error on future!");
}
Exception: happened error on future!

onError と catchError の違いはなんなのか?

上記の説明だと onError と catchError は同じ機能なのではという疑問が浮かび上がってくるがそうではない。then の onError では then の onValue で発生した例外は処理できない仕組みになっている。一方 catchError は then の onValue で発生した例外も処理できる仕組みになっている。

// onValue というのは then で値を受け取ったときの処理を記述する then の引数
Future<R> then<R>(FutureOr<R> onValue(T value), {Function? onError});

例えば以下のように Future の then で受け取った値を変換するときに例外が発生したとする。その場合に onError を利用すると値の変換で発生した例外を処理できない。

void main() {
  var future = createFuture();
  future.then((value) => print("get ${convert(value)}"), onError: (e) => print("${e}}"));
}

Future<int> createFuture() async {
  return 0;
}

String convert(int number) {
  throw Exception("invalid number.");
}
// 例外をキャッチできていない、なので onError の処理が呼び出されていない
Uncaught Error: Exception: invalid number.

catchError を利用するのであれば値の変換で発生した例外を処理できる。

void main() {
  var future = createFuture();
  future.then((value) => print("get ${convert(value)}")).catchError((e) => print("Catch ${e}"));
}

Future<int> createFuture() async {
  return 0;
}

String convert(int number) {
  throw Exception("invalid number.");
}
// 例外をキャッチできている、onError の処理が呼び出されている
Exception: invalid number.

というように onError と catchError は同じように見えますが then の onValue で発生した例外を処理できるかどうかというところに違いがある。

Discussion