我有一个Flutter应用程序,我在其中使用SQFLITE插件从Sqlite数据库中获取数据。在这里,我面临一个奇怪的问题。根据我的理解,我们使用async / await或then()函数进行异步编程。 在这里,我有一个db.query()方法,该方法正在执行一些SQL查询以从db获取数据。在此函数获取数据之后,我们将在.then()函数中进行一些进一步的处理。但是,用这种方法我遇到了一些问题。从我调用此getExpensesByFundId(int fundId)函数的位置来看,它似乎无法正确获取数据。它应该返回Future>对象,然后在数据可用时将其转换为List。但是当我打电话时它不起作用。
但是,我只是对其进行了一些试验,并在db.query()函数前面添加了“ await”关键字,并且以某种方式使其开始可以正常工作。您能否解释为什么添加await关键字可以解决此问题?我以为在使用.then()函数时,我们不需要使用await关键字。
这是我的代码:
minusMonths
答案 0 :(得分:4)
简单地说:
await
旨在中断流程直到异步方法完成。
then
不会中断处理流程(意味着将执行下一条指令),但是使您可以在异步方法完成后运行代码。
在您的示例中,使用then
时无法实现所需的功能,因为代码未在“等待”状态,并且return
语句已处理并因此返回空列表。
添加await
时,您明确地说:“直到我的Future
完成(then
部分)之后,再说。
您仅可以使用await
编写以下代码来达到相同的结果:
Future<List<Expense>> getExpensesByFundId(int fundId) async {
Database db = await database;
List<Expense> expenseList = List();
List<Map<String,dynamic>> expList = await db.query(expTable,where: '$expTable.$expFundId = $fundId');
expList.forEach((Map<String, dynamic> expMap) {
expenseList.add(Expense.fromMap(expMap));
});
return expenseList;
}
您还可以选择仅使用then
部分,但是您需要确保随后正确调用getExpensesByFundId
:
Future<List<Expense>> getExpensesByFundId(int fundId) async {
Database db = await database;
List<Expense> expenseList = List();
return db.query(expTable,where: '$expTable.$expFundId = $fundId')
.then((List<Map<String,dynamic>> expList){
expList.forEach((Map<String, dynamic> expMap){
expenseList.add(Expense.fromMap(expMap));
});
});
}
// call either with an await
List<Expense> list = await getExpensesByFundId(1);
// or with a then (knowing that this will not interrupt the process flow and process the next instruction
getExpensesByFundId(1).then((List<Expense> l) { /*...*/ });
答案 1 :(得分:0)
在使类使用async
来使用await
时,它的简单逻辑是在函数中建立等待状态,直到检索到要显示的数据为止。
示例:1)就像您单击按钮时一样2)数据首先存储在数据库中,然后使用Future
函数来检索数据3)将数据移动到变量中,然后在屏幕上显示4)变量显示为增量在您的关注/个人资料中。
then
一步一步地使用代码,将数据存储在变量中,然后移至下一个。
示例:如果我单击“跟随”按钮,直到变量中的数据存储,它将连续检索一些数据以存储,并且不允许下一个函数运行,并且如果一项任务完成而不是转移到另一项任务。
与您的问题一样,我也在社交媒体Flutter应用程序中进行实验,这是我的理解。我希望这会有所帮助。
答案 2 :(得分:0)
添加到以上答案中。
Flutter Application被认为是逐步执行代码,但事实并非如此。 在应用程序的生命周期中将触发许多事件,例如Click Event,Timer等。必须在后台线程中运行一些代码。
后台工作的执行方式:
所以有两个Queues
Microtask Queue
运行不应由任何事件(单击,计时器等)运行的代码。它可以同时包含同步和异步工作。
Event Queue
在应用程序中发生任何外部Click事件(如Click事件)时运行,然后在事件循环内完成该块执行。
下图将详细说明执行过程。
注意::在应用程序开发的任何给定点,微任务队列都会运行,然后只有事件队列才能运行。
答案 3 :(得分:0)
使用期货:异步,等待,然后和期货
async
和await
关键字提供了一种声明性的方式来定义异步函数并使用它们的结果。使用async
和await
时,请记住以下两个基本准则:
async
:await
关键字仅在async
函数中起作用。下面是将main()
从同步功能转换为异步功能的示例。
首先,在函数正文之前添加async
关键字:
void main() async { ··· }
如果函数具有声明的返回类型,则将类型更新为Future<T>
,其中T是函数返回的值的类型。如果该函数未明确返回值,则返回类型为Future<void>
:
Future<void> main() async { ··· }
现在您有了async
函数,可以使用await
关键字等待将来完成:
print(await createOrderMessage());
.Then((value){…})
是future
成功完成(带有值)时调用的回调。
await createOrderMessage().then((value) {...});
异步,等待,然后和未来的完整示例
Future<String> createOrderMessage() async {
var order = await fetchUserOrder();
return 'Your order is: $order';
}
Future<String> fetchUserOrder() =>
// Imagine that this function is
// more complex and slow.
Future.delayed(
Duration(seconds: 2),
() => 'Large Latte',
);
Future<void> main() async {
print('Fetching user order...');
print(await createOrderMessage().then((value) {
print(value);
return value;
}));
}