【问题标题】:Chaining Dart futures - possible to access intermediate results?链接 Dart 期货 - 可以访问中间结果吗?
【发布时间】:2014-02-27 22:34:18
【问题描述】:

Dart 允许chaining futures 在不嵌套回调的情况下按顺序调用多个异步方法,这很棒。

假设我们要先连接到像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");
  }

四种异步方法,但代码相当容易阅读和理解。看起来这些步骤几乎是同步和按顺序执行的。美丽的! (想象一下必须使用嵌套的 JavaScript 回调编写相同的代码......)

不幸的是,这完全行不通:我们从.connect 方法获得的RedisClient 仅分配给一个局部变量,该变量不在后续.thens 的范围内。所以,redisClient.smembersredisClient.get 实际上会抛出一个空指针异常。

显而易见的解决方法是将返回值保存在另一个具有函数作用域的变量中:

  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 表达式,添加一对花括号和一个 @987654329 @ 语句和另一个分号。

既然这似乎是一种常见的模式,有没有更优雅的方式来做到这一点?有什么方法可以访问更下游的那些早期中间体?

【问题讨论】:

    标签: dart dart-async


    【解决方案1】:

    您可以使用嵌套赋值来避免大括号和return

    .then((RedisClient rc) => (redisClient = rc).exists(indexKey))
    

    【讨论】:

    • 不错!不知道您可以在表达式中嵌套赋值。
    【解决方案2】:

    你也可以用期货做范围,不要把所有的'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"); 
            );
    

    这样的代码总是很难缩进。此示例遵循 Dart 样式指南,但我认为它可以通过更少的 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"); 
        );
    

    【讨论】:

    • 也是一个很好的答案。我更喜欢@AlexandreArdhuin 的解决方案,因为它避免了任何嵌套。
    猜你喜欢
    • 1970-01-01
    • 2023-03-20
    • 2011-02-08
    • 2018-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-13
    • 1970-01-01
    相关资源
    最近更新 更多