10

Dart では、Future を連鎖させて、コールバックをネストすることなく、複数の非同期メソッドを順番に呼び出すことができます。これは素晴らしいことです。

最初にRedisのようなデータ ストアに接続し、一連の順次読み取りを実行したいとします。

  Future<String> FirstValue(String indexKey)
  { 
    return RedisClient.connect(Config.connectionStringRedis)
      .then((RedisClient redisClient) => redisClient.exists(indexKey))
      .then((bool exists) => !exists ? null : redisClient.smembers(indexKey))
      .then((Set<String> keys) => redisClient.get(keys.first))
      .then((String value) => "result: $value");
  }

4 つの非同期メソッドがありますが、コードは非常に読みやすく、理解しやすいものです。ステップが同期して順番に実行されているように見えます。美しい!(ネストされた JavaScript コールバックを使用して同じコードを書かなければならないことを想像してみてください...)

残念ながら、これはうまくいきませんメソッドから取得した RedisClient は、後続の s の.connectスコープ外のローカル変数にのみ割り当てられます。.thenそのため、redisClient.smembers実際redisClient.getには null ポインター例外がスローされます。

明らかな修正は、戻り値を関数スコープを持つ別の変数に保存することです。

  Future<String> FirstValue(String indexKey)
  { 
    RedisClient redisClient = null;
    return RedisClient.connect(Config.connectionStringRedis)
      .then((RedisClient theRedisClient) 
          {
            redisClient = theRedisClient;
            return redisClient.exists(indexKey); 
          })
      .then((bool exists) => !exists ? null : redisClient.smembers(indexKey))
      .then((Set<String> keys) => redisClient.get(keys.first))
      .then((String value) => "result: $value");    
  }

残念ながら、これによりコードがより冗長になり、見栄えが悪くなります。追加のヘルパー変数 (theRedisClient) があり、Lambda 式の 1 つを匿名関数に置き換えて、中かっこのペアとreturnステートメントと別のセミコロンを追加する必要がありました。

これは一般的なパターンのように見えるので、これを行うよりエレガントな方法はありますか? チェーンのさらに下にある以前の中間にアクセスする方法はありますか?

4

2 に答える 2

3

すべての「then」呼び出しを同じレベルに置かないことで、先物でもスコープを実行できます。私は次のようなことをします:

Future<String> FirstValue(String indexKey) => 
    RedisClient.connect(Config.connectionStringRedis)
        .then((RedisClient redisClient) =>
             redisClient.exists(indexKey)
                 .then((bool exists) => !exists ? null : redisClient.smembers(indexKey))
                 .then((Set<String> keys) => redisClient.get(keys.first))
                 .then((String value) => "result: $value"); 
        );

このようなコードでは、インデントは常に困難です。thenこの例は Dart スタイル ガイドに従っていますが、呼び出しのインデントを減らすと読みやすくなると思います。

Future<String> FirstValue(String indexKey) => 
    RedisClient.connect(Config.connectionStringRedis)
    .then((RedisClient redisClient) =>
         redisClient.exists(indexKey)
         .then((bool exists) => !exists ? null : redisClient.smembers(indexKey))
         .then((Set<String> keys) => redisClient.get(keys.first))
         .then((String value) => "result: $value"); 
    );
于 2014-02-28T09:12:10.087 に答える