什么是 Future 以及如何使用它?
What is a Future and how do I use it?
我收到以下错误:
A value of type 'Future<int>' can't be assigned to a variable of type 'int'
可能是另一种类型而不是int
,但基本上模式是
A value of type 'Future<T>' can't be assigned to a variable of type 'T'
所以...
Future
到底是什么?
- 如何得到我想得到的实际值?
- 当我只有
Future<T>
时,我可以使用什么小部件来显示我的值?
如果您熟悉 Task<T>
or Promise<T>
和 async
/ await
模式,那么您可以直接跳到“如何使用 Future with Flutter 中的小部件”部分。
什么是 Future 以及如何使用它?
嗯,documentation 说:
An object representing a delayed computation.
没错。它也有点抽象和干燥。通常,函数 return 是一个结果。按顺序。函数被调用,运行s 和 returns 是结果。在此之前,调用者等待。某些功能,尤其是当它们访问硬件或网络等资源时,需要一些时间才能完成。想象一下从 Web 服务器加载头像图片,从数据库加载用户数据,或者只是从设备内存加载多种语言的应用程序文本。那可能会很慢。
默认情况下,大多数应用程序只有一个控制流。当此流程被阻塞时,例如等待需要时间的计算或资源访问,应用程序就会冻结。如果你足够大,你可能会记得这是标准的,但在当今世界,这将被视为一个错误。即使有些事情需要时间,我们也会得到一点动画。一个微调器,一个沙漏,也许是一个进度条。但是,一个应用程序 运行 并显示动画,但仍然等待结果怎么办?答案是:异步操作。在您的代码等待某些东西时仍然 运行 的操作。现在编译器如何知道,它是应该停止一切并等待结果,还是继续所有后台工作并仅在这种情况下等待?好吧,它无法自己解决这个问题。我们必须告诉它。
这是通过称为 async and await. It's not specific to flutter or dart, it exists under the same name in many other languages. You can find the documentation for Dart here 的模式实现的。
由于需要一些时间的方法无法立即 return,因此它将 return 承诺在完成后交付价值。
那叫一个Future
。因此,从数据库中加载一个数字的承诺将 return Future<int>
而 return 来自互联网搜索的电影列表的承诺可能 return Future<List<Movie>>
]. Future<T>
是 将来 会给你一个 T
.
让我们尝试不同的解释:
A future represents the result of an asynchronous operation, and can have two states: uncompleted or completed.
很有可能,因为您不是为了好玩而这样做,您实际上需要 Future<T>
的结果来推进您的应用程序。您需要显示数据库中的编号或找到的电影列表。所以你想等,直到结果出来。这是 await
的用武之地:
Future<List<Movie>> result = loadMoviesFromSearch(input);
// right here, you need the result. So you wait for it:
List<Movie> movies = await result;
但是等等,我们还没有回到原点吗?不是又要等结果了吗?是的,我们确实是。如果程序没有某种类似于顺序流的东西,它们将是完全混乱的。但重点是我们使用关键字 await
告诉编译器,此时,虽然我们想要等待结果,但我们不希望我们的应用程序只是冻结。我们希望所有其他 运行ning 操作(例如动画)继续。
但是,您只能在本身标记为 async
和 return 和 Future<T>
的函数中使用关键字 await
。因为当你 await
某些东西时,正在等待的函数不能再立即 return 它们的结果。你只能return你有什么,如果你必须等待,你必须return承诺稍后交付。
Future<Pizza> getPizza() async {
Future<PizzaBox> delivery = orderPizza();
var pizzaBox = await delivery;
var pizza = pizzaBox.unwrap();
return pizza;
}
我们的 getPizza 函数必须 等待 披萨,所以不是 return 立即 Pizza
,它必须 return保证将来 会有披萨 。现在您可以反过来 await
某处的 getPizza 函数。
如何在 Flutter 的小部件中使用 Future?
flutter 中的所有小部件都需要真实值。不是对稍后出现的价值的承诺。当按钮需要文本时,它不能使用文本稍后出现的承诺。它需要显示按钮 now,因此它需要文本 now.
但有时,您拥有的只是 Future<T>
。这就是 FutureBuilder
的用武之地。您可以在有未来时使用它,在等待时显示一件事(例如进度指示器),在完成时显示另一件事(例如结果) .
让我们来看看我们的披萨示例。您想要订购比萨饼,您想要在等待时看到进度指示器,您想要在交付后看到结果,并且可能在出现错误时显示错误消息:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
/// ordering a pizza takes 5 seconds and then gives you a pizza salami with extra cheese
Future<String> orderPizza() {
return Future<String>.delayed(const Duration(seconds: 5), () async => 'Pizza Salami, Extra Cheese');
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark(),
home: Scaffold(
body: Center(
child: PizzaOrder(),
),
),
);
}
}
class PizzaOrder extends StatefulWidget {
@override
_PizzaOrderState createState() => _PizzaOrderState();
}
class _PizzaOrderState extends State<PizzaOrder> {
Future<String>? delivery;
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: delivery != null ? null : () => setState(() { delivery = orderPizza(); }),
child: const Text('Order Pizza Now')
),
delivery == null
? const Text('No delivery scheduled')
: FutureBuilder(
future: delivery,
builder: (context, snapshot) {
if(snapshot.hasData) {
return Text('Delivery done: ${snapshot.data}');
} else if(snapshot.hasError) {
return Text('Delivery error: ${snapshot.error.toString()}');
} else {
return const CircularProgressIndicator();
}
})
]);
}
}
这就是您使用 FutureBuilder 来显示您的未来结果的方式。
Future<T>
返回将由 async
work
完成的潜在价值
例如:
Future<int> getValue() async {
return Future.value(5);
}
上面的代码返回 Future.value(5)
是 int
类型,但是从方法接收值时我们不能使用类型 Future<int>
即
Future<int> value = await getValue(); // Not Allowed
// Error
A value of type 'Future<int>' can't be assigned to a variable of type 'int'
解决上面的getValue()应该在int
类型下接收
int value = await getValue(); // right way as it returning the potential value.
下面是来自其他语言的 Dart Future
的类比列表:
- JS:
Promise
- Java:
Future
- Python:
Future
- C#:
Task
就像在其他语言中一样,Future 是一种特殊类型的对象,它允许使用 async/await 语法糖,以 synchronous/linear 方式编写异步代码。您 return 来自异步方法的 Future 而不是接受回调作为参数并避免回调地狱 - Futures 和回调都解决了相同的问题(稍后触发一些代码)但方式不同。
我希望这个关键点能提供信息,我用两种不同的异步方法展示它:
请注意以下方法,其中 showLoading()
、getAllCarsFromApi()
和 hideLoading()
是内部 Async
方法。
如果我将 await
关键字放在 showLoading()
之前,Operation 会等到它完成然后转到下一行,但我有意删除了 await
因为我需要我的 Loading 对话框与正在处理的 getAllCarsFromApi()
同时显示,所以这意味着 showLoading()
和 getAllCarsFromApi()
方法已处理在不同的 线程 上。最后 hideLoading()
隐藏加载对话框。
Future<List<Car>> getData() async{
showLoading();
final List<Car> cars = await getAllCarsFromApi();
hideLoading();
return cars;
}
再看看这个Async
方法,这里getCarByIdFromApi()
方法需要一个id
,它是从getCarIdFromDatabase()
计算出来的,所以必须有一个await
关键字在第一个方法之前使 Operation 等到 id
被计算并传递给第二个方法。所以这里两个方法一个接一个地在一个Thread.
中处理
Future<Car> getCar() async{
int id = await getCarIdFromDatabase();
final Car car = await getCarByIdFromApi(id);
return car;
}
一个简单的答案是,如果一个函数returns它的值与某个时间的delay
有关,Future
用于获取它的值。
Future<int> calculate({required int val1, required int val2}) async {
await Future.delayed(const Duration(seconds: 2));
return val1 + val2;
}
如果我们调用上面的函数为
getTotal() async {
int result = calculate(val1: 5, val2: 5);
print(result);
}
我们会得到以下错误:
A value of type 'Future<int>' can't be assigned to a variable of type 'int'
但是如果我们在函数调用之前使用 await,它将在延迟后给出函数的实际返回值
getTotal() async {
int result = await calculate(val1: 5, val2: 5);
print(result);
}
需要关键字 async
才能使用 await
Future 获取返回值
我收到以下错误:
A value of type 'Future<int>' can't be assigned to a variable of type 'int'
可能是另一种类型而不是int
,但基本上模式是
A value of type 'Future<T>' can't be assigned to a variable of type 'T'
所以...
Future
到底是什么?- 如何得到我想得到的实际值?
- 当我只有
Future<T>
时,我可以使用什么小部件来显示我的值?
如果您熟悉 Task<T>
or Promise<T>
和 async
/ await
模式,那么您可以直接跳到“如何使用 Future with Flutter 中的小部件”部分。
什么是 Future 以及如何使用它?
嗯,documentation 说:
An object representing a delayed computation.
没错。它也有点抽象和干燥。通常,函数 return 是一个结果。按顺序。函数被调用,运行s 和 returns 是结果。在此之前,调用者等待。某些功能,尤其是当它们访问硬件或网络等资源时,需要一些时间才能完成。想象一下从 Web 服务器加载头像图片,从数据库加载用户数据,或者只是从设备内存加载多种语言的应用程序文本。那可能会很慢。
默认情况下,大多数应用程序只有一个控制流。当此流程被阻塞时,例如等待需要时间的计算或资源访问,应用程序就会冻结。如果你足够大,你可能会记得这是标准的,但在当今世界,这将被视为一个错误。即使有些事情需要时间,我们也会得到一点动画。一个微调器,一个沙漏,也许是一个进度条。但是,一个应用程序 运行 并显示动画,但仍然等待结果怎么办?答案是:异步操作。在您的代码等待某些东西时仍然 运行 的操作。现在编译器如何知道,它是应该停止一切并等待结果,还是继续所有后台工作并仅在这种情况下等待?好吧,它无法自己解决这个问题。我们必须告诉它。
这是通过称为 async and await. It's not specific to flutter or dart, it exists under the same name in many other languages. You can find the documentation for Dart here 的模式实现的。
由于需要一些时间的方法无法立即 return,因此它将 return 承诺在完成后交付价值。
那叫一个Future
。因此,从数据库中加载一个数字的承诺将 return Future<int>
而 return 来自互联网搜索的电影列表的承诺可能 return Future<List<Movie>>
]. Future<T>
是 将来 会给你一个 T
.
让我们尝试不同的解释:
A future represents the result of an asynchronous operation, and can have two states: uncompleted or completed.
很有可能,因为您不是为了好玩而这样做,您实际上需要 Future<T>
的结果来推进您的应用程序。您需要显示数据库中的编号或找到的电影列表。所以你想等,直到结果出来。这是 await
的用武之地:
Future<List<Movie>> result = loadMoviesFromSearch(input);
// right here, you need the result. So you wait for it:
List<Movie> movies = await result;
但是等等,我们还没有回到原点吗?不是又要等结果了吗?是的,我们确实是。如果程序没有某种类似于顺序流的东西,它们将是完全混乱的。但重点是我们使用关键字 await
告诉编译器,此时,虽然我们想要等待结果,但我们不希望我们的应用程序只是冻结。我们希望所有其他 运行ning 操作(例如动画)继续。
但是,您只能在本身标记为 async
和 return 和 Future<T>
的函数中使用关键字 await
。因为当你 await
某些东西时,正在等待的函数不能再立即 return 它们的结果。你只能return你有什么,如果你必须等待,你必须return承诺稍后交付。
Future<Pizza> getPizza() async {
Future<PizzaBox> delivery = orderPizza();
var pizzaBox = await delivery;
var pizza = pizzaBox.unwrap();
return pizza;
}
我们的 getPizza 函数必须 等待 披萨,所以不是 return 立即 Pizza
,它必须 return保证将来 会有披萨 。现在您可以反过来 await
某处的 getPizza 函数。
如何在 Flutter 的小部件中使用 Future?
flutter 中的所有小部件都需要真实值。不是对稍后出现的价值的承诺。当按钮需要文本时,它不能使用文本稍后出现的承诺。它需要显示按钮 now,因此它需要文本 now.
但有时,您拥有的只是 Future<T>
。这就是 FutureBuilder
的用武之地。您可以在有未来时使用它,在等待时显示一件事(例如进度指示器),在完成时显示另一件事(例如结果) .
让我们来看看我们的披萨示例。您想要订购比萨饼,您想要在等待时看到进度指示器,您想要在交付后看到结果,并且可能在出现错误时显示错误消息:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
/// ordering a pizza takes 5 seconds and then gives you a pizza salami with extra cheese
Future<String> orderPizza() {
return Future<String>.delayed(const Duration(seconds: 5), () async => 'Pizza Salami, Extra Cheese');
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark(),
home: Scaffold(
body: Center(
child: PizzaOrder(),
),
),
);
}
}
class PizzaOrder extends StatefulWidget {
@override
_PizzaOrderState createState() => _PizzaOrderState();
}
class _PizzaOrderState extends State<PizzaOrder> {
Future<String>? delivery;
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: delivery != null ? null : () => setState(() { delivery = orderPizza(); }),
child: const Text('Order Pizza Now')
),
delivery == null
? const Text('No delivery scheduled')
: FutureBuilder(
future: delivery,
builder: (context, snapshot) {
if(snapshot.hasData) {
return Text('Delivery done: ${snapshot.data}');
} else if(snapshot.hasError) {
return Text('Delivery error: ${snapshot.error.toString()}');
} else {
return const CircularProgressIndicator();
}
})
]);
}
}
这就是您使用 FutureBuilder 来显示您的未来结果的方式。
Future<T>
返回将由 async
work
例如:
Future<int> getValue() async {
return Future.value(5);
}
上面的代码返回 Future.value(5)
是 int
类型,但是从方法接收值时我们不能使用类型 Future<int>
即
Future<int> value = await getValue(); // Not Allowed
// Error
A value of type 'Future<int>' can't be assigned to a variable of type 'int'
解决上面的getValue()应该在int
类型下接收
int value = await getValue(); // right way as it returning the potential value.
下面是来自其他语言的 Dart Future
的类比列表:
- JS:
Promise
- Java:
Future
- Python:
Future
- C#:
Task
就像在其他语言中一样,Future 是一种特殊类型的对象,它允许使用 async/await 语法糖,以 synchronous/linear 方式编写异步代码。您 return 来自异步方法的 Future 而不是接受回调作为参数并避免回调地狱 - Futures 和回调都解决了相同的问题(稍后触发一些代码)但方式不同。
我希望这个关键点能提供信息,我用两种不同的异步方法展示它:
请注意以下方法,其中 showLoading()
、getAllCarsFromApi()
和 hideLoading()
是内部 Async
方法。
如果我将 await
关键字放在 showLoading()
之前,Operation 会等到它完成然后转到下一行,但我有意删除了 await
因为我需要我的 Loading 对话框与正在处理的 getAllCarsFromApi()
同时显示,所以这意味着 showLoading()
和 getAllCarsFromApi()
方法已处理在不同的 线程 上。最后 hideLoading()
隐藏加载对话框。
Future<List<Car>> getData() async{
showLoading();
final List<Car> cars = await getAllCarsFromApi();
hideLoading();
return cars;
}
再看看这个Async
方法,这里getCarByIdFromApi()
方法需要一个id
,它是从getCarIdFromDatabase()
计算出来的,所以必须有一个await
关键字在第一个方法之前使 Operation 等到 id
被计算并传递给第二个方法。所以这里两个方法一个接一个地在一个Thread.
Future<Car> getCar() async{
int id = await getCarIdFromDatabase();
final Car car = await getCarByIdFromApi(id);
return car;
}
一个简单的答案是,如果一个函数returns它的值与某个时间的delay
有关,Future
用于获取它的值。
Future<int> calculate({required int val1, required int val2}) async {
await Future.delayed(const Duration(seconds: 2));
return val1 + val2;
}
如果我们调用上面的函数为
getTotal() async {
int result = calculate(val1: 5, val2: 5);
print(result);
}
我们会得到以下错误:
A value of type 'Future<int>' can't be assigned to a variable of type 'int'
但是如果我们在函数调用之前使用 await,它将在延迟后给出函数的实际返回值
getTotal() async {
int result = await calculate(val1: 5, val2: 5);
print(result);
}
需要关键字 async
才能使用 await
Future 获取返回值