Future
Future是Flutter中表示异步操作结果的对象。当我们需要执行一个耗时的操作时,可以将其封装在一个Future对象中,然后继续执行其他任务,而不需要等待该操作完成。一旦操作完成,Future将提供该操作的结果。通常使用async和await关键字来处理Future。例如,我们可以创建一个返回Future的异步函数:
Future<int> fetchData() async {
// 模拟一个耗时的操作
await Future.delayed(Duration(seconds: 1));
return 0;
}
然后,我们可以在其他地方调用这个异步函数,并使用await关键字等待其结果:
void main() async {
int data = await fetchData();
print('data = $data');
}
当fetchData异步操作完成后,await将得到该操作的结果,并继续执行后续代码。
Completer
Completer是Flutter中用于手动完成Future的对象。有时候我们需要手动控制一个异步任务的完成,并将其结果传递给Future,这时就可以使用Completer。通过Completer,我们可以创建一个未完成的Future,并在合适的时机手动完成它。下面是一个示例:
Future<int> fetchData() {
Completer<int> completer = Completer();
// 模拟一个耗时的操作
Future.delayed(Duration(seconds: 1), () {
completer.complete(0); // 手动完成Future并传递结果
});
return completer.future;
}
我们创建了一个Completer对象,然后在异步任务完成时调用completer.complete(result)来完成Future并传递结果。
使用这个Completer的方法和之前的Future使用方式是相同的:
void main() async {
int data = await fetchData();
print('data = $data');
}
上述代码中,我们等待异步任务完成,Completer将传递的结果提供给了Future。
注意:宣告完成的complete和completeError方法只能调用一次,不然会报错。
compute
在一个页面中做耗时比较大的运算时,就算用了async / await异步处理, UI页面的动画还是会卡顿,因为还是在这个UI线程中做运算,异步只是说可以先运行其他的,等有结果再返回,但是记住,我们的计算仍旧是在这个UI线程,仍会阻塞UI的刷新,异步只是在同一个线程的并发操作。要解决这个卡顿问题,可以把运算移到另一个线程中,在dart中,这里不是称呼线程,是Isolate,直译叫做隔离,是因为隔离不共享数据,每个隔离中的变量都是不同的,不能相互共享。
Isolate的操作比较复杂,dart中封装了一层简单的实现
/// package:flutter/foundation.dart
Future<R> Function<Q, R>(FutureOr<R> Function(Q), Q, {debugLabel: String})compute
使用方法
import 'package:flutter/foundation.dart';
function callback( val ){
...
return res
}
/// `callback` 必须是顶级方法或者是类的静态方法
var res = await compute( callback , val );
总结
Future、Completer、compute三者都可以用于处理异步任务,但它们在用法上有一些差异。
Future会自动在异步任务完成时提供结果,而Completer允许手动控制Future的完成。使用async和await关键字可以使异步代码更加简洁易读,因此在绝大多数情况下,使用Future更为常见。 根据实际需求,如果你需要手动控制异步任务的完成,可以使用Completer,否则通常使用Future即可。
如果一个任务需要几百毫秒或之上的,为了避免UI线程卡顿建议使用compute(只有一次返回)或Isolate(用于订阅或有多次返回的)
如果方法执行在几毫秒或十几毫秒左右的,建议使用使用Future或Completer