Dart Async 做其他事情然后等待
Dart Async Do Something Else Then Wait
我已经阅读了几个 Whosebug 问题、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();
}
}
getCredit(credit_id)
不仅启动异步调用,它还 returns 一个 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 一样,并不是真正的多线程,像那样忙于等待会永远阻塞事件循环,阻止将设置 [=27 的代码=] 从 运行.
async
和 await
的一般工作原理的简短总结:
Future someFunc(args) async {
...
return value;
}
相当于:
Future someFunc(args) {
return new Future(() => {
...
return value;
}
}
内部代码在事件循环的后续迭代中执行,返回的 future 要么以 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
本身,或者您可以 await
任意 [=17] =] 对象,无论它来自哪里。
但是 - 这就是 await
和 async
如此方便的原因 - 你可以从 [=20= 有 5 个不同的出口点] 函数穿插在 13 个嵌套循环、开关、try/catch 和 if
块内的不同位置的三个 await
调用(在同一个 async
函数中),Dart 将自动找出必要的回调树,使其全部遵循相同的代码路径,就好像所有调用都是同步的一样。
我已经阅读了几个 Whosebug 问题、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();
}
}
getCredit(credit_id)
不仅启动异步调用,它还 returns 一个 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 一样,并不是真正的多线程,像那样忙于等待会永远阻塞事件循环,阻止将设置 [=27 的代码=] 从 运行.
async
和 await
的一般工作原理的简短总结:
Future someFunc(args) async {
...
return value;
}
相当于:
Future someFunc(args) {
return new Future(() => {
...
return value;
}
}
内部代码在事件循环的后续迭代中执行,返回的 future 要么以 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
本身,或者您可以 await
任意 [=17] =] 对象,无论它来自哪里。
但是 - 这就是 await
和 async
如此方便的原因 - 你可以从 [=20= 有 5 个不同的出口点] 函数穿插在 13 个嵌套循环、开关、try/catch 和 if
块内的不同位置的三个 await
调用(在同一个 async
函数中),Dart 将自动找出必要的回调树,使其全部遵循相同的代码路径,就好像所有调用都是同步的一样。