這可能是一個反復出現的問題,但我發現了相互矛盾的答案,我現在很困惑其中哪個是正確的。我以為我理解了這個概念,然后我開始閱讀所有這些答案并感到完全困惑,所以我正在尋找我可以輕松理解的明確而簡單的問題答案。
根據this answer和this article,await應該中斷代碼執行并實際等待未來完成,然后繼續按順序執行其余代碼。它還表明這可能會阻塞主執行緒,這在這種情況下才合乎邏輯。
另一方面,來自 flutter 團隊的this、this和this 視頻表明,這await 不會阻止其余的代碼執行,它只是在未來完成時注冊要執行的回呼的語法糖,這與then做。
現在,我嘗試撰寫一個小程式來了解哪些是正確的,似乎第一種方法是要走的路:
import 'dart:async';
// prints:
// 1000
// 1000
void main() async {
Stopwatch watch = Stopwatch();
watch.start();
await Future.delayed(Duration(seconds:1)).then((_){print(watch.elapsedMilliseconds);});
print(watch.elapsedMilliseconds);
}
反對:
import 'dart:async';
// prints:
// 0
// 1000
void main() async {
Stopwatch watch = Stopwatch();
watch.start();
Future.delayed(Duration(seconds:1)).then((_){print(watch.elapsedMilliseconds);});
print(watch.elapsedMilliseconds);
}
所以我只想知道為什么 flutter 團隊和一些人建議這await不會阻止代碼執行以及這個概念是如何真正起作用的。
uj5u.com熱心網友回復:
實際上,您的兩個函式都具有相同的Result,讓我更清楚地解釋一下..
當呼叫異步函式時,它們只是don't block我們應用程式的其他部分來呈現。無論我們在內部執行什么操作delayed,其余部分都將按原樣進行。
現在讓我們來看看你的例子
import 'dart:async';
// prints 1000
void main() async {
Stopwatch watch = Stopwatch();
watch.start();
await Future.delayed(Duration(seconds:1));
print(watch.elapsedMilliseconds);
}
在上面的示例中,您只是通過了delay duration而不是callback。因此,它將其余部分視為完成callback后將被呼叫的duration部分。現在你在做什么,你告訴你的函式等待你提供了進一步代碼的Durationexecute。
所以結果是1000
在下面的例子中
import 'dart:async';
// prints:
// 0
// 1000
void main() async {
Stopwatch watch = Stopwatch();
watch.start();
Future.delayed(Duration(seconds:1)).then((_){print(watch.elapsedMilliseconds);}); // prints 1000
print(watch.elapsedMilliseconds); // prints 0
}
您正在正確地將 a 分配callback給Future。所以現在Future將只保留它callback,讓其余部分完成。
這就是它先列印0然后再delay列印1000 的原因。
而且 Future 和 Future 延遲有不同的作業流程,這可能是現在使用 await 或不使用的正確方法。
uj5u.com熱心網友回復:
我認為對阻塞存在一些誤解。當您查看第一個示例時 - await 將僅阻止執行函式中的其余代碼。您的應用程式的其余部分仍然可以正常作業。
您需要了解一件事:async/await 語法只是 .then(callback) 語法的一種語法糖。它們都實作了相同的目標,只有 async/await 更容易閱讀、除錯和理解。正如您所看到的 - 在您的兩個示例中,您都得到了相同的結果。你的問題是:你更喜歡哪種語法?
為了澄清 - 讓我們假設您想引入幾個 1 秒的等待事件,并在每個事件之后寫一條訊息。
您的第一個示例將如下所示:
import 'dart:async';
// prints 1000
void main() async {
Stopwatch watch = Stopwatch();
watch.start();
await Future.delayed(Duration(seconds:1));
print(watch.elapsedMilliseconds);
await Future.delayed(Duration(seconds:1));
print(watch.elapsedMilliseconds);
await Future.delayed(Duration(seconds:1));
print(watch.elapsedMilliseconds);
}
請注意閱讀和理解代碼是多么容易。
現在,將第二個示例更改為實作相同的功能:
import 'dart:async';
void main() async {
Stopwatch watch = Stopwatch();
watch.start();
Future.delayed(Duration(seconds:1)).then((_){
print(watch.elapsedMilliseconds);
Future.delayed(Duration(seconds:1)).then((_){
print(watch.elapsedMilliseconds);
Future.delayed(Duration(seconds:1)).then((_){
print(watch.elapsedMilliseconds);
});
});
});
}
他們都會達到同樣的效果——但第二個例子會讓你的眼睛受傷。
您需要考慮的一個更有趣的場景是 - 如果您希望同時發生幾件事怎么辦?這并不罕見 - 如果您需要從 3 個不同的服務器獲取 3 個影像,則不會按順序獲取它們。您可能希望同時觸發所有 3 個請求,并等待所有請求完成。
使用 async/await 這很容易:
import 'dart:async';
// prints 1000
void main() async {
Stopwatch watch = Stopwatch();
watch.start();
var f1 = Future.delayed(Duration(seconds:1));
var f2 = Future.delayed(Duration(seconds:2));
var f3 = Future.delayed(Duration(seconds:3));
await Future.wait([f1, f2, f3]);
print(watch.elapsedMilliseconds);
}
請注意,因為我們沒有在每個 Future.delayed 前面放置 await - 這意味著我們將啟動延遲的未來,但我們不會等待它完成。
您會看到整個功能只需要 3 秒即可完成;因為所有 3 個計時器都在同時運行。Future.wait 將等待期貨串列完成。
Now - it is pretty clear that you don't really need .then() syntax in most of the cases, but I think it will still be applicable in more complex scenarios.
For example: you need to fetch 3 images from 3 servers. Each of those servers has a backup server; if the first server returns null as a result - you need to fetch the resource from the backup server. Additionaly: if Backup server 1 or Backup server 2 returned null, you need to call server 4 to get a single image.
You could even plot a small graph describing this. Now this is where .then() syntax comes in handy - and we will still combine it with async/await. I think once you fully understand this example - you pretty much understand async/await and .then(). Let's go:
import 'dart:async';
import 'dart:math';
Future<int?> getImage(String server) async {
var rng = Random();
print("Downloading from $server");
// we'll add random delay to simulate network
await Future.delayed(Duration(seconds: rng.nextInt(5)));
print("$server is done");
// high chance of returning null
if (rng.nextInt(10)<7) return null;
return 1;
}
// prints 1000
void main() async {
Stopwatch watch = Stopwatch();
watch.start();
// get the image from server 1
var f1 = getImage("Server 1").then((data) async {
return data ?? await getImage("Server 1 backup");
});
var f2 = getImage("Server 2").then((data) async {
return data ?? await getImage("Server 2 backup");
});
var f4=Future.wait([f1, f2]).then((data) async {
if (data[0]==null || data[1]==null) return [await getImage("Server 4")];
});
var f3 = getImage("Server 3").then((data) async {
return data ?? await getImage("Server 3 backup");
});
await Future.wait([f3, f4]);
print("elapsed ${watch.elapsedMilliseconds} ms");
}
這里的一個新東西是: .then() 將回傳一個未來的物件 - 您仍然可以使用 await 關鍵字等待。告訴你這是一樣的事情......
如果沒有 .then() 語法,您可以啟動服務器 1 和服務器 2;但是你必須選擇:我該等哪一個?如果您等待它們都完成 - 您可能是在浪費時間:如果服務器 1 回傳 null,您將等待服務器 2 完成,然后才能呼叫服務器 1 備份。
當事情是線性的時,標準的 async/await 會有所幫助(比如我展示的多個 Future.delayed 示例)。但是,當您遇到可以通過 Graph 描述且多個分支并行運行的復雜場景時 - .then() 將派上用場。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/382751.html
下一篇:為不同的JSON檔案撰寫類
