狐好きぷろぐらまー

狐好きプログラマーのブログです。

【Dart】rxdartについて調べてみる 第12回目 - concatWithとdebounce- 【rxdart】

こんにちは。pregum_foxです。

前回から3年ほど開いて、rxdartのバージョンも0.27.7になりましたが、久しぶりに書いていきたいと思います。

みたところ0.23.x以降は大きな変更はないみたいなので、とりあえず最新バージョンで色々書いていきます。

今回は、concatWithとdebounceについてです。

今までの一覧は下記記事に記載しています。

目次です。

動作環境

動作環境は以下の通りです。

項目 バージョン
dart 3.0.6
rxdart 0.27.7

以下にconcatWithオペレータとdebounceオペレータについて気足します。 名称はRx、rxdart、Stream APIの順で記載していきます。

concatWithオペレータ

シグネチャ

  • rxdart

Stream<T> concatWith(Iterable<Stream<T>> other)

ConcatStream<T> ConcatStream(Iterable<Stream<T>> streams)

処理の概要

引数に渡されたStreamを順番に出力します。

import 'package:rxdart/rxdart.dart';

Future studyConcatWith() async {
  // 1のstreamを発行
  Stream.value(1)
      // 複数のstreamを順番に追加していく
      .concatWith([
    // 0~4までのstreamを発行
    Stream.periodic(Duration(milliseconds: 100), (int i) => i).take(5),
    // 5~9までのstreamを発行
    Stream.periodic(Duration(milliseconds: 100), (int i) => i).skip(5).take(5),
  ]).listen(print, onDone: () => print('on done.'));
}


// ===実行結果===
// 1
// 0
// 1
// 2
// 3
// 4
// 5
// 6
// 7
// 8
// 9
// on done.

debounceオペレータ

シグネチャ

  • rxdart

Stream<T> debounce(Stream Function(T event) window)

DebounceStreamTransformer<T> DebounceStreamTransformer(Stream Function(T event) window)

処理の概要

引数に渡されたイベントの最後の発行から指定した期間経った後、その時最後に渡されているイベントを次のオペレータに渡します。

言葉だと分かりにくいと思うのでサンプルコードをみて下さい。

import 'package:rxdart/rxdart.dart';

Future studyDebounce() async {
  // 500ms毎にカウントアップするストリームを生成する
  Stream.periodic(Duration(milliseconds: 500), (int i) => i)
      // 値発行から300ms後にイベントを発火する
      .debounce((event) {
        print('debounde: $event');
        return TimerStream(true, Duration(milliseconds: 300));
      })
      // 5要素取得する
      .take(5)
      .listen(print, onDone: () => print('on done.'));

  // 区切る為に少し待つ
  await Future.delayed(const Duration(milliseconds: 3000));
  print('--------------------------------------------------');

// 100ms毎にカウントアップするストリームを生成する
  Stream.periodic(Duration(milliseconds: 100), (int i) => i)
      // 5要素取得する
      .take(5)
      // この場合、300ms経つ前に次の値が先に来る為、フィルタされる
      .debounce((event) {
    print('debounde: $event');
    return TimerStream(true, Duration(milliseconds: 300));
  }).listen(print, onDone: () => print('on done.'));

  // 区切る為に少し待つ
  await Future.delayed(const Duration(milliseconds: 4000));
  print('--------------------------------------------------');

// 100ms毎にカウントアップするストリームを生成する
  Stream.periodic(Duration(milliseconds: 100), (int i) => i)
      // 5要素取得する
      .take(5)
      // 偶数のみ通す
      .debounce(
    (event) {
      print('debounde: $event, isEven: ${event.isEven}');
      if (event.isEven) {
        // trueでなくてもとりあえず値を返せば良い
        return Stream.value(true);
      } else {
        // 値は返さないといけないので、実質無限に遅延するStreamを返す
        return TimerStream(true, Duration(days: 99999));
      }
    },
  ).listen(print, onDone: () => print('on done.'));
}


// ===実行結果===
// debounde: 0
// 0
// debounde: 1
// 1
// debounde: 2
// 2
// debounde: 3
// 3
// debounde: 4
// 4
// on done.
// --------------------------------------------------
// debounde: 0
// debounde: 1
// debounde: 2
// debounde: 3
// debounde: 4
// 4
// on done.
// --------------------------------------------------
// debounde: 0, isEven: true
// 0
// debounde: 1, isEven: false
// debounde: 2, isEven: true
// 2
// debounde: 3, isEven: false
// debounde: 4, isEven: true
// 4
// on done.

雑感

3年ぶりに書いてみましたが、一覧があってどこから書いていけば良いかすぐわかったので、このままの勢いで月二ぐらいのペースでかけると良いなと思います。

ここまで読んで頂き、ありがとうございました。

参考サイト