イベント ループとイベント キュー
Future はスレッドではないことに注意してください。それらは同時に実行されません。実際、Dart はシングルスレッドです。すべての Dart コードはイベント ループで実行されます。
イベント ループは、現在のDart アイソレートが生きている限り実行されるループです。Dart アプリケーションを開始するために呼び出すmain()
と、isolate が作成され、main メソッドが完了し、イベント キューのすべてのアイテムも完了すると、それはアクティブではなくなります。
イベント キューは、実行を完了する必要があるすべての関数のセットです。Dart はシングル スレッドであるため、これらの関数はすべて一度に 1 つずつ実行する必要があります。したがって、イベント キュー内の 1 つの項目が完了すると、別の項目が開始されます。イベント キューの正確なタイミングとスケジューリングは、私が説明できるよりもはるかに複雑です。
したがって、非同期処理は、実行時間の長い実行によって単一のスレッドがブロックされるのを防ぐために重要です。UI では、プロセスに時間がかかると視覚的なジャンクが発生し、アプリの動作が妨げられる可能性があります。
先物
先物は、将来のある時点で利用可能になる値を表すため、その名前が付けられています。Future が作成されると、すぐに返され、実行が続行されます。
その Future (あなたの場合はexpensiveFunction
) に関連付けられたコールバックは、イベント キューに追加されることによって「開始」されます。現在の分離から戻ると、コールバックが実行され、できるだけ早くthen
.
ストリーム
Future は定義上非同期であり、いつ戻るかわからないため、コールバックをキューに入れ、順序を維持する必要があります。
Streamは、サブスクライブできるイベントを発行するオブジェクトです。あなたが書くとき、あなたは のストリームをcanvasElement.onClick.listen(...)
求めています。それを でサブスクライブします。onClick
MouseEvents
listen
Streams を使用してイベントをキューに入れ、それらのイベントにコールバックを登録して、必要なコードを実行できます。
何を書くか
main() {
// Used to add events to a stream.
var controller = new StreamController<Future>();
// Pause when we get an event so that we take one value at a time.
var subscription = controller.stream.listen(
(_) => subscription.pause());
var canvas = new CanvasElement();
canvas.onClick.listen((MouseEvent e) {
print("entering event handler");
var future = new Future<int>(expensiveFunction);
// Resume subscription after our callback is called.
controller.add(future.then(redrawCanvas).then(subscription.resume()));
print("done event handler");
});
}
expensiveFunction() {
for(int i = 0; i < 1000000000; i++){
//do something insane here
}
}
redrawCanvas(int value) {
//do stuff here
print("redrawing canvas");
}
ここではredrawCanvas
、マウスをクリックするたびに一時停止し、呼び出し後に再開することで、コールバックをキューに入れredrawCanvas
ています。
詳しくは
同様の質問に対するこの素晴らしい回答も参照してください。
Dart の非同期性について読み始めるのに最適な場所は、dart:io ライブラリに関するこの記事の最初の部分と、dart:async ライブラリに関するこの記事の最初の部分です。
Futures の詳細については、Futures に関するこの記事を参照してください。
Streams の情報については、Streams への追加に関するこの記事とStreams の作成に関するこの記事を参照してください。