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");
}
四种异步方法,但代码相当容易阅读和理解。看起来这些步骤几乎是同步和按顺序执行的。美丽的!(想象一下必须使用嵌套的 JavaScript 回调编写相同的代码......)
不幸的是,这不太行得通:我们从.connect
方法中获得的 RedisClient 只分配给了一个局部变量,该变量不在后续.then
s 的范围内。所以,redisClient.smembers
实际上redisClient.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 表达式,添加一对花括号和一个return
语句以及另一个分号。
既然这似乎是一种常见的模式,有没有更优雅的方法呢?有什么方法可以在链条的下游访问那些早期的中间体?