【问题标题】:Dart Flutter, help me understand futuresDart Flutter,帮我理解期货
【发布时间】:2020-10-17 04:33:35
【问题描述】:

查看此代码:

class SomeClass{
  String someVariable;
  SomeClass();
  
  Future<String> getData ()  async {
    Response response = await get('http://somewebsite.com/api/content');
    
    Map map = jsonDecode(response.body); // do not worry about statuscode, trying to keep it minimal
    someVariable = map['firstName'];
    return 'This is the first name : $someVariable';
  }
}

现在看看 main:

void main(){
  String someFunction() async {
    SomeClass instance = SomeClass(); // creating object
    String firstNameDeclaration = await instance.getData().then((value) => value); 
    return firstNameDeclaration;
  }
}

在使用 Future 时,例如在 firstNameDeclaration 的情况下,为什么我必须使用 .then() 方法来访问字符串对象,因为我正在等待函数完成? 在网上搜索时,有些人使用.then()其他人没有,我很困惑。

请帮助我更清楚地了解 Futures 和异步函数的整体工作原理。

【问题讨论】:

标签: flutter asynchronous dart future


【解决方案1】:

背景

异步操作让您的程序在等待另一个操作完成的同时完成工作。以下是一些常见的异步操作:

  • 通过网络获取数据。
  • 正在写入数据库。
  • 从文件中读取数据。

要在 Dart 中执行异步操作,您可以使用 Future 类以及 asyncawait 关键字。

当异步函数调用“await”时,它会被转换为 Future,并放入执行队列中。当等待的未来完成时,调用函数被标记为准备好执行,它将在稍后的某个时间点恢复。重要的区别是在此模型中不需要暂停线程。

期货与异步等待

当一个async函数调用“await”时,它会被转换成一个Future,并放入执行队列中。当等待的未来完成时,调用函数被标记为准备好执行,它将在稍后的某个时间点恢复。重要的区别是在此模型中不需要暂停线程。

async-await 只是一种定义异步函数并将其结果用于 Future 的声明方式,它提供了语法糖来帮助您编写涉及 Futures 的干净代码。

考虑一下这个涉及期货的飞镖代码 -

Future<String> getData(int number) {
  return Future.delayed(Duration(seconds: 1), () {
    return 'this is a future string $number.';
  });
}

main(){
  getData(10).then((data) => {
    print(data)
  });
}

正如您在使用 Futures 时所看到的,您可以在函数返回未来值时使用 then 回调。如果只有一个“then”回调,这很容易管理,但是例如,一旦有许多嵌套的“then”回调,情况就会迅速升级 -

Future<String> getProductCostForUser() {
  return getUser().then((user) => {
    var uid = user.id;
    return getOrder(uid).then((order) => {
      var pid = order.productId;
      return getProduct(pid).then((product) => {
        return product.totalCost;
      });
    });
  });
}

main(){
  getProductCostForUser().then((cost) => {
    print(cost);
  });
}

当有多个链接的“then”回调时,代码变得非常难以阅读和管理。 "async-await" 解决了这个问题。上面的链式“then”回调可以通过使用 "async-await" 来简化 -

Future<String> getProductCostForUser() async {
  var user = await getUser();
  var order = await getOrder(user.uid);
  var product = await getProduct(order.productId);
  return product.totalCost;
}

main() async {
  var cost = await getProductCostForUser();
  print(cost);
}

如您所见,当存在链式“then”回调时,上面的代码更具可读性和易于理解。

我希望这能解释一些关于“async-await”和 Futures 的基本概念和理解。

您可以进一步阅读主题和示例here

【讨论】:

  • 非常感谢,感谢您详尽而清晰的回答。
【解决方案2】:

基本上,您应该使用awaitthen()。然而,Dart guidelines 主张你应该更喜欢使用await 而不是then()

这段代码:

Future<int> countActivePlayers(String teamName) {
  return downloadTeam(teamName).then((team) {
    if (team == null) return Future.value(0);

    return team.roster.then((players) {
      return players.where((player) => player.isActive).length;
    });
  }).catchError((e) {
    log.error(e);
    return 0;
  });
}

应替换为:

Future<int> countActivePlayers(String teamName) async {
  try {
    var team = await downloadTeam(teamName);
    if (team == null) return 0;

    var players = await team.roster;
    return players.where((player) => player.isActive).length;
  } catch (e) {
    log.error(e);
    return 0;
  }
}

在你的情况下,你应该写:

void main(){
  Future<String> someFunction() async {
    SomeClass instance = SomeClass(); // creating object
    String firstNameDeclaration = await instance.getData();
    return firstNameDeclaration;
    // Or directly : return await instance.getData();
    // Or : return instance.getData();
  }
}

【讨论】:

  • 有时混合使用这两种类型是有益的。由于then() 也返回一个Future,它可用于在将结果分配给变量之前对其进行操作(例如String body = await httpFuture.then((response) =&gt; response.body)
  • 我明白你的意思,但我宁愿写String body = (await httpFuture()).body;
  • 是的,你是对的。在这种情况下,我想这取决于个人喜好。
  • someFunction() 如何不会产生编译错误?如果使用 async 关键字,方法是否必须返回 Future
猜你喜欢
  • 2020-10-14
  • 2020-01-30
  • 2019-08-06
  • 2017-03-26
  • 1970-01-01
  • 1970-01-01
  • 2020-11-25
  • 2020-05-09
  • 2014-08-06
相关资源
最近更新 更多