【问题标题】:Dart Async Do Something Else Then WaitDart Async 做其他事情然后等待
【发布时间】:2016-09-20 22:44:38
【问题描述】:

我已经阅读了几个 stackoverflow 问题、dart 文档,甚至还观看了有关 async 和 await 的视频。我还没有找到我的问题的答案。我想调用一个异步方法,执行其他代码,然后等待异步任务完成。

这是我正在使用的示例。这是我的组件

Credit credit;
...
Future<Null> getCredit(id) async {
  try {
    credit = await _creditService.getCredit(id);
  }
  catch (e) {
    errorMessage = e.toString();
  }
}
...
void onUpdateCredit(int credit_id) {
  getCredit(credit_id);
  creditDialogTitle = 'Update Credit';
  creditArtistIndex = credit.artist_id;
  instrument = credit.instrument;
  creditNotes = credit.notes;
  creditDialog.open();
}

此代码崩溃,因为尝试使用它时信用为空。一种解决方法是结合这两种方法:

Future<Null> onUpdateCredit(id) async {
  try {
    credit = await _creditService.getCredit(id);
    creditDialogTitle = 'Update Credit';
    creditArtistIndex = credit.artist_id;
    instrument = credit.instrument;
    creditNotes = credit.notes;
    creditDialog.open();
  }
  catch (e) {
    errorMessage = e.toString();
  }
}

没有什么是并行的,如果我需要代码中其他地方的功劳,我将不得不复制该方法的 try/catch 部分。我也可以这样编码:

void onUpdateCredit(int credit_id) {
  credit = null;
  getCredit(credit_id);
  creditDialogTitle = 'Update Credit';
  while (credit == null) {//wait a period of time}
  creditArtistIndex = credit.artist_id;
  instrument = credit.instrument;
  creditNotes = credit.notes;
  creditDialog.open();
}

在其他情况下,我在我的 html 中使用 *ngIf="var != null" 执行类似的操作,其中 var 由未来填充。

有没有比使用 while (credit == null) 更好的方法?此示例仅在请求和完成之间执行一条指令,因此很简单。我敢肯定,我会在其他情况之间有很多事情要做。我也在添加服务方法:

Future<Credit> getCredit(int id) async {
  try {
    String url = "http://catbox.loc/credits/${id.toString()}";
    HttpRequest response = await HttpRequest.request(
        url, requestHeaders: headers);
    Map data = JSON.decode(response.responseText);
    final credit = new Credit.fromJson(data);
    return credit;
  }
  catch (e) {
    throw _handleError(e);
  }
}

更新

根据@Douglas 的回答,这是可行的:

Future<Null> onUpdateCredit(id) async {
  Future future = getCredit(id);
  creditDialogTitle = 'Update Credit';
  await future;
  creditArtistIndex = credit.artist_id;
  instrument = credit.instrument;
  creditNotes = credit.notes;
  creditDialog.open();
}

然后我消除了干预方法。

Future<Null> onUpdateCredit(id) async {
  try {
    Future<Credit> future =  _creditService.getCredit(id);
    creditDialogTitle = 'Update Credit';
    credit = await future;
    creditArtistIndex = credit.artist_id;
    instrument = credit.instrument;
    creditNotes = credit.notes;
    creditDialog.open();
  }
  catch (e) {
    errorMessage = e.toString();
    }
}

【问题讨论】:

    标签: dart angular-dart


    【解决方案1】:

    getCredit(credit_id) 不仅启动异步调用,它还立即返回一个Future 对象。将该对象存储在一个局部变量中,您可以稍后在它完成时使用它来异步执行其他代码。

    有两种方法可以使用 Future 对象。更简单、更流畅的方式要求您将onUpdateCredit 声明为async。在async 函数中,await futureObject 行将导致该行之后的所有代码在Future 完成后异步执行。使用这种技术的 onUpdateCredit 的完整版本如下所示:

    Future<Null> onUpdateCredit(int credit_id) async {
      Future future = getCredit(credit_id);
      creditDialogTitle = 'Update Credit';
      await future;
      creditArtistIndex = credit.artist_id;
      instrument = credit.instrument;
      creditNotes = credit.notes;
      creditDialog.open();
    }
    

    另一种方法是使用.then() 将其余代码显式注册为回调。看起来像这样:

    void onUpdateCredit(int credit_id) {
      Future future = getCredit(credit_id);
      creditDialogTitle = 'Update Credit';
      future.then((_) => {
        creditArtistIndex = credit.artist_id;
        instrument = credit.instrument;
        creditNotes = credit.notes;
        creditDialog.open();
      });
    }
    

    请注意,无论哪种情况,如果异常路径出现在getCredit(id) 中,您将收到credit 未设置的错误。如果您真的希望异常被静默吞下,您应该让其处理程序为 credit 填写默认值,以便假定它正常完成的代码仍然可以工作。

    另外请注意,您的 while 循环版本会失败 - Dart 和 JavaScript 一样,不是真正的多线程,并且像这样忙于等待会永远阻塞事件循环,从而阻止设置 credit 的代码运行。

    asyncawait 工作原理的简短总结:

    Future someFunc(args) async {
      ...
      return value;
    }
    

    相当于:

    Future someFunc(args) {
      return new Future(() => {
        ...
        return value;
      }
    }
    

    里面的代码在事件循环的后续迭代中执行,返回的未来要么成功完成value,要么异常地完成该代码中抛出的任何内容。

    与此同时:

    try {
      value = await someFutureObject;
      ...more code here...
    } catch (e) {
      ...exception handling here...
    }
    

    相当于:

    someFutureObject.then((value) => {
      ...more code here...
    }).catchError((e) => {
      ...exception handling here...
    });
    

    最常见的用例是someVar = await someAsyncCall();,但您可以通过省略await 来保存Future 本身,或者您可以在任意Future 对象上使用await,无论它来自何处。

    然而 - 这就是 awaitasync 如此方便的原因 - 您可以从 async 函数中获得 5 个不同的退出点,其中穿插三个 await 调用(在相同的 async 函数)在 13 个嵌套循环、开关、try/catch 和 if 块内的各种位置,Dart 将自动找出必要的回调树,使其全部遵循相同的代码路径,就好像所有调用是同步的。

    【讨论】:

    • 感谢您的澄清。我读过几篇关于未来回归的文章,但没有关于如何使用它的示例。
    • 当我去查找一个示例时,我同意 while 循环,它们非常复杂。 Dart 没有等待(时间)。
    • 那么如果getCredit(id) 中的try catch 捕获到错误,它会设置错误信息,并在await 将来继续处理?如果是这样,是否会在 onUpdateCredit 中添加一个 try catch 来解决问题? _creditService.getCredit 方法还包含一个 try catch。如果我需要添加第三个,摆脱 getCredit 并直接调用 _creditService.getCredit 似乎是有意义的。
    • @curt Dart 的 wait(time) 的异步兼容非阻塞等效项是 await Future.delayed(time)。这将在指定时间后将其余代码作为事件循环的回调,并且与 await 关键字的所有用法一样,仅允许在 async 函数中使用。在 onUpdateCredit 中的 await 周围添加 try/catch 仅在删除 getCredit 中的 getCredit 时才会有所帮助,从而允许传播异常。您可以改为进行空检查,但我同意 getCredit 在您显示的代码中没有增加太多价值。
    • @curt 另外,你了解.then().catchError()等在期货上的用法吗?如果您已经了解函数概念,我可以非常简洁地解释 asyncawait 如何映射到基于函数的等效项。
    猜你喜欢
    • 2015-11-01
    • 2011-10-09
    • 1970-01-01
    • 2021-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多