2020/11/24 Asynchronous programming: streamsの訳

ポイントは何ですか?

  • ストリームは、データの非同期シーケンスを提供します。

  • シーケンス:複数のデータの連続(のような意味)

  • データシーケンスには、ユーザーが生成したイベントとファイルから読み取られたデータが含まれます。

  • streamを進める方法として「await forを使う方法」と「StreamAPIのlisten()メソッドを使う方法」があります。

  • ストリームは、エラーに応答する方法を提供します。

  • ストリームには、シングルサブスクリプションとブロードキャストの2種類があります。

Dartの非同期プログラミングはFutureクラスとStreamクラスを使用します。

Futureは即時に完了しない(時間がかかる)計算(とその結果)を表現します。通常の関数が結果を返すのに対し、非同期関数はFutureを返します。

Futureは最終的には結果の値(あるいはエラー)を返します。futureは結果がいつ返ってきたかを教えてくれます。

streamは複数の複数の非同期イベントの連続を表現します。streamは非同期なイテラブルのようなものです。

要求したときに次のイベントを取得する代わりに、準備ができたときにイベントがあることをストリームが通知します。


Receiving stream events

streamを生成する方法はいくつもありますが、それについては他の記事で説明します。

streamを生成する方法に対して、streamを使用する(結果を受け取る)方法は一つです。

await for(asynchronous for loop)を使って、streamのイベントをイテレート(一つずつ順番に処理する)します。例えば、

Future<int> sumStream(Stream<int> stream) async {
  var sum = 0

2020/6/10 Creating streams in Dart

dart:asyncライブラリは他の多くのDart APIにとって重要な二つの型、StreamとFutureクラスを含んでいます。Futureクラスは一つの計算の結果を表し、Streamクラスは複数の計算の結果を表します。streamをlistenすることで結果(データ、あるいはエラーの両方)が届いたことの通知を受けます。listen中にポーズ(一時停止)することもできますし、streamが完了する前にlistenを止めることもできます。

この記事ではstreamの使い方に関しての記事ではありません。streamの作り方に関しての記事です。streamを作るためにはいくつかの方法があります。

  • 既存のstreamを変換する。
  • async*関数(ジェネレータ関数)を用いて一からstreamを作る。
  • StreamControllerインスタンスを用いてstreamを作る。

この記事ではそれぞれのアプローチのサンプルコードを示します。


Transforming an existing stream

一般的なstreamの作り方は、すでにあるstreamのイベントを基にして新しい別のstreamを作る方法です。例えば、入力をUTF-8デコーディングして、既にある「bytesのstream」を「文字列のstream」に変換したいとします。最も一般的なアプローチは、オリジナルのstreamの各イベントの結果を待って新しいイベントを出力する新しいstreamを作ることです。

sample1

/// Splits a stream of consecutive strings into lines.
///
/// The input string is provided in smaller chunks through
/// the `source` stream.
Stream<String> lines(Stream<String> source) 

2020/6/8 dart:async – asynchronous programming(stream))

Stream

Dart APIsのStreamオブジェクトは、複数の非同期処理の結果を表現します。例えば、ボタンのクリックのようなHTMLイベントはstreamを使って届けられます。ファイルもstreamとして読み込むことができます。

Using an asynchronous for loop

Stream APIの代わりに非同期なforループ(await for)を使うことができます。

sample1-1ではStreamクラスのlisten()メソッドでファイルのリストをリッスン(subscribe(購読))しています。listenメソッドの引数に、それぞれのファイルをサーチする関数リテラルを渡しています。

sample1-1の関数について考えましょう。

sample1-1

void main(List<String> arguments) {
  // ...
  FileSystemEntity.isDirectory(searchPath).then((isDir) {
    if (isDir) {
      final startingDir = Directory(searchPath);
      startingDir
          .list(
              recursive: argResults[recursive],
              followLinks: argResults[followLinks])
          .listen((entity) {
        if (entity is 

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のようになります。…