patorashのブログ

方向性はまだない

List.forEachでasync, awaitしたいならFuture.forEachを使おう

これはDart Advent Calendar 2017の15日目の投稿です。

qiita.com

カレンダーがガラガラで寂しかったので、メモ書きですが、参加しました。

今コツコツとDartでちょっとしたゲームアプリを作ろうとしているのですが、1秒ごとに処理を行いたいと考えていました。もちろんDartなので非同期で。

1秒ごとに処理がされない

最初はこれでいけるんじゃないか?と思って書いてみました。

main() {
  List<Foo> foos = []
  for(int i = 0; i < 20; i++) {
    Foo foo = new Foo();
    // なんやかんやで…
    foos.add(foo);
  }

  foos.forEach((foo) async {
    await new Future.delayed(new Duration(seconds: 1));
    foo.bar();
  });
}

こうすると、1秒ごとに20秒まで処理が行われ…ずに、1秒後に20個分の処理結果がドンと表示されました。 よくよく見ると、たしかにそうなるわなぁ…と思います。

これで1秒ごとに処理できる!

for inを使えばできるが…

for inを使えば、処理はできましたが、forはなんかダサイ…。しかもその処理の関数にasyncつけないといけなくなるのでいただけない。

main() async { // 上の関数にasyncつけないといけない
  // foosを作る処理は省略
  for(foo in foos) {
    await new Future.delayed(new Duration(seconds: 1));
    foo.bar();
  }
}

Future.forEachを使おう

これが一番綺麗でわかりやすいです。イテレータが渡される関数にasyncをつけるだけでよいので見た目もいいですね。

main() { // 上の関数にasync必要なし!
  // foosを作る処理は省略
  Future.forEach(foos, (foo) async { // こちらにasyncをつける。
    await new Future.delayed(new Duration(seconds: 1));
    foo.bar();
  });
}
参考リンク

api.dartlang.org