Dart Async做其他事情然后等待

时间:2016-09-20 22:44:38

标签: dart angular-dart

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

这是我正在使用的一个例子。这是我的组件

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();
}

此代码崩溃,因为尝试使用它时,credit为null。解决这个问题的一种方法是结合两种方法:

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();
    }
}

1 个答案:

答案 0 :(得分:3)

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();,但您可以通过省略Future来保存await,也可以await对任意Future进行保存对象,无论它来自何处。

然而 - 这就是让awaitasync非常方便的原因 - 你可以从async函数中有5个不同的退出点,其中散布着三个await调用(在同一async函数中)13个嵌套循环,开关,try / catch和if块内的各种位置,Dart将自动找出必要的回调树使所有这些都遵循相同的代码路径,就好像所有调用都是同步的一样。