Flutter开发进阶之瞧瞧Future
在Flutter开发中,异步编程是处理较长时间的操作(网络请求、文件I/O、复杂计算任务等)的方式,而不会阻塞主线程的执行。
在异步操作中,Future是代表异步操作最终可能完成的对象,这个对象会在将来的某个时间点完成,并带有操作的结果或异常。
这篇文章将从基本概念和用法去了解Future。
让我们看看Future的源码,以下。
("wasm:entry-point")
abstract interface class Future<T> {
static final _Future<Null> _nullFuture = nullFuture as _Future<Null>;
static final _Future<bool> _falseFuture =
new _Future<bool>.zoneValue(false, _rootZone);
factory Future(FutureOr<T> computation()) {
_Future<T> result = new _Future<T>();
Timer.run(() {
try {
result._complete(computation());
} catch (e, s) {
_completeWithErrorCallback(result, e, s);
}
});
return result;
}
factory Future.microtask(FutureOr<T> computation()) {
_Future<T> result = new _Future<T>();
scheduleMicrotask(() {
try {
result._complete(computation());
} catch (e, s) {
_completeWithErrorCallback(result, e, s);
}
});
return result;
}
factory Future.sync(FutureOr<T> computation()) {
try {
var result = computation();
if (result is Future<T>) {
return result;
} else {
return new _Future<T>.value(result as dynamic);
}
} catch (error, stackTrace) {
var future = new _Future<T>();
AsyncError? replacement = Zone.current.errorCallback(error, stackTrace);
if (replacement != null) {
future._asyncCompleteError(replacement.error, replacement.stackTrace);
} else {
future._asyncCompleteError(error, stackTrace);
}
return future;
}
}
("vm:entry-point")
("vm:prefer-inline")
factory Future.value([FutureOr<T>? value]) {
return new _Future<T>.immediate(value == null ? value as T : value);
}
factory Future.error(Object error, [StackTrace? stackTrace]) {
checkNotNullable(error, "error");
if (!identical(Zone.current, _rootZone)) {
AsyncError? replacement = Zone.current.errorCallback(error, stackTrace);
if (replacement != null) {
error = replacement.error;
stackTrace = replacement.stackTrace;
}
}
stackTrace ??= AsyncError.defaultStackTrace(error);
return new _Future<T>.immediateError(error, stackTrace);
}
factory Future.delayed(Duration duration, [FutureOr<T> computation()?]) {
if (computation == null && !typeAcceptsNull<T>()) {
throw ArgumentError.value(
null, "computation", "The type parameter is not nullable");
}
_Future<T> result = new _Future<T>();
new Timer(duration, () {
if (computation == null) {
result._complete(null as T);
} else {
try {
result._complete(computation());
} catch (e, s) {
_completeWithErrorCallback(result, e, s);
}
}
});
return result;
}
("vm:recognized", "other")
static Future<List<T>> wait<T>(Iterable<Future<T>> futures,
{bool eagerError = false, void cleanUp(T successValue)?}) {
final _Future<List<T>> _future = _Future<List<T>>();
List<T?>? values;
int remaining = 0;
late Object error;
late StackTrace stackTrace;
void handleError(Object theError, StackTrace theStackTrace) {
remaining--;
List<T?>? valueList = values;
if (valueList != null) {
if (cleanUp != null) {
for (var value in valueList) {
if (value != null) {
T cleanUpValue = value;
new Future.sync(() {
cleanUp(cleanUpValue);
});
}
}
}
values = null;
if (remaining == 0 || eagerError) {
_future._completeError(theError, theStackTrace);
} else {
error = theError;
stackTrace = theStackTrace;
}
} else if (remaining == 0 && !eagerError) {
_future._completeError(error, stackTrace);
}
}
try {
for (var future in futures) {
int pos = remaining;
future.then((T value) {
remaining--;
List<T?>? valueList = values;
if (valueList != null) {
valueList[pos] = value;
if (remaining == 0) {
_future._completeWithValue(List<T>.from(valueList));
}
} else {
if (cleanUp != null && value != null) {
new Future.sync(() {
cleanUp(value);
});
}
if (remaining == 0 && !eagerError) {
_future._completeError(error, stackTrace);
}
}
}, onError: handleError);
remaining++;
}
if (remaining == 0) {
return _future.._completeWithValue(<T>[]);
}
values = new List<T?>.filled(remaining, null);
} catch (e, st) {
if (remaining == 0 || eagerError) {
return new Future.error(e, st);
} else {
error = e;
stackTrace = st;
}
}
return _future;
}
static Future<T> any<T>(Iterable<Future<T>> futures) {
var completer = new Completer<T>.sync();
void onValue(T value) {
if (!completer.isCompleted) completer.complete(value);
}
void onError(Object error, StackTrace stack) {
if (!completer.isCompleted) completer.completeError(error, stack);
}
for (var future in futures) {
future.then(onValue, onError: onError);
}
return completer.future;
}
static Future<void> forEach<T>(
Iterable<T> elements, FutureOr action(T element)) {
var iterator = elements.iterator;
return doWhile(() {
if (!iterator.moveNext()) return false;
var result = action(iterator.current);
if (result is Future) return result.then(_kTrue);
return true;
});
}
static bool _kTrue(Object? _) => true;
static Future<void> doWhile(FutureOr<bool> action()) {
_Future<void> doneSignal = new _Future<void>();
late void Function(bool) nextIteration;
nextIteration = Zone.current.bindUnaryCallbackGuarded((bool keepGoing) {
while (keepGoing) {
FutureOr<bool> result;
try {
result = action();
} catch (error, stackTrace) {
_asyncCompleteWithErrorCallback(doneSignal, error, stackTrace);
return;
}
if (result is Future<bool>) {
result.then(nextIteration, onError: doneSignal._completeError);
return;
}
keepGoing = result as bool;
}
doneSignal._complete(null);
});
nextIteration(true);
return doneSignal;
}
Future<R> then<R>(FutureOr<R> onValue(T value), {Function? onError});
Future<T> catchError(Function onError, {bool test(Object error)?});
Future<T> whenComplete(FutureOr<void> action());
Stream<T> asStream();
Future<T> timeout(Duration timeLimit, {FutureOr<T> onTimeout()?});
}
其中@pragma("wasm:entry-point")
用于指示WASM编译器作为入口,可以在Web浏览器中安全、快速的运行。
@vmIsolateUnsendable
表示某个类或对象必须要在Dart的隔离(Isolate
)环境,确保线程安全。
一般在我们更多使用factory Future(FutureOr<T> computation())
,我们可以看到Future
是通过Timer
执行异步操作,然后等到有结果后再返回结果。
让我们看看定时器的创建过程,以下。
Timer createTimer(Zone zone, Duration duration, void f()) {
var implementation = _delegationTarget._createTimer;
_Zone implZone = implementation.zone;
CreateTimerHandler handler = implementation.function;
return handler(implZone, implZone._parentDelegate, zone, duration, f);
}
继续查看官方注释,以下。
/// The type of a custom [Zone.createTimer] implementation function.
///
/// Receives the [Zone] that the handler was registered on as [self],
/// a delegate forwarding to the handlers of [self]'s parent zone as [parent],
/// and the current zone where the error was uncaught as [zone],
/// which will have [self] as a parent zone.
///
/// The callback function [f] and [duration] are the ones which were
/// passed to [Zone.createTimer] of [zone]
/// (possibly through the [Timer] constructor).
///
/// The custom handler can choose to replace the function [f]
/// with one that does something before, after or instead of calling [f],
/// and then call `parent.createTimer(zone, replacement)`.
/// or it can implement its own timer queue, which typically
/// still depends on `parent.createTimer` to as a way to get started.
///
/// The function should return a [Timer] object which can be used
/// to inspect and control the scheduled timer callback.
///
/// The function must only access zone-related functionality through
/// [self], [parent] or [zone].
/// It should not depend on the current zone ([Zone.current]).
typedef CreateTimerHandler = Timer Function(Zone self, ZoneDelegate parent,
Zone zone, Duration duration, void Function() f);
以上可知系统会有一个专门处理定时器的Zone
的队列。
让我们继续查看factory Future.microtask(FutureOr<T> computation())
,它的异步是通过void scheduleMicrotask(void Function() callback)
进行操作,让我们继续看看void scheduleMicrotask(void Function() callback)
的注释,以下。
/// Runs [callback] asynchronously in this zone.
///
/// The global `scheduleMicrotask` delegates to the [current] zone's
/// [scheduleMicrotask]. The root zone's implementation interacts with the
/// underlying system to schedule the given callback as a microtask.
///
/// Custom zones may intercept this operation (for example to wrap the given
/// [callback]), or to implement their own microtask scheduler.
/// In the latter case, they will usually still use the parent zone's
/// [ZoneDelegate.scheduleMicrotask] to attach themselves to the existing
/// event loop.
void scheduleMicrotask(void Function() callback);
可知这种异步是通过微任务调度器进行异步操作的,它与Timer
的区别是什么呢?让我们看看Zone
是怎么处理的,以下。
_CustomZone(this.parent, ZoneSpecification specification, this._map)
: _run = parent._run,
_runUnary = parent._runUnary,
_runBinary = parent._runBinary,
_registerCallback = parent._registerCallback,
_registerUnaryCallback = parent._registerUnaryCallback,
_registerBinaryCallback = parent._registerBinaryCallback,
_errorCallback = parent._errorCallback,
_scheduleMicrotask = parent._scheduleMicrotask,
_createTimer = parent._createTimer,
_createPeriodicTimer = parent._createPeriodicTimer,
_print = parent._print,
_fork = parent._fork,
_handleUncaughtError = parent._handleUncaughtError {
// The root zone will have implementations of all parts of the
// specification, so it will never try to access the (null) parent.
// All other zones have a non-null parent.
var run = specification.run;
if (run != null) {
_run = _ZoneFunction<RunHandler>(this, run);
}
var runUnary = specification.runUnary;
if (runUnary != null) {
_runUnary = _ZoneFunction<RunUnaryHandler>(this, runUnary);
}
var runBinary = specification.runBinary;
if (runBinary != null) {
_runBinary = _ZoneFunction<RunBinaryHandler>(this, runBinary);
}
var registerCallback = specification.registerCallback;
if (registerCallback != null) {
_registerCallback =
_ZoneFunction<RegisterCallbackHandler>(this, registerCallback);
}
var registerUnaryCallback = specification.registerUnaryCallback;
if (registerUnaryCallback != null) {
_registerUnaryCallback = _ZoneFunction<RegisterUnaryCallbackHandler>(
this, registerUnaryCallback);
}
var registerBinaryCallback = specification.registerBinaryCallback;
if (registerBinaryCallback != null) {
_registerBinaryCallback = _ZoneFunction<RegisterBinaryCallbackHandler>(
this, registerBinaryCallback);
}
var errorCallback = specification.errorCallback;
if (errorCallback != null) {
_errorCallback = _ZoneFunction<ErrorCallbackHandler>(this, errorCallback);
}
var scheduleMicrotask = specification.scheduleMicrotask;
if (scheduleMicrotask != null) {
_scheduleMicrotask =
_ZoneFunction<ScheduleMicrotaskHandler>(this, scheduleMicrotask);
}
var createTimer = specification.createTimer;
if (createTimer != null) {
_createTimer = _ZoneFunction<CreateTimerHandler>(this, createTimer);
}
var createPeriodicTimer = specification.createPeriodicTimer;
if (createPeriodicTimer != null) {
_createPeriodicTimer =
_ZoneFunction<CreatePeriodicTimerHandler>(this, createPeriodicTimer);
}
var print = specification.print;
if (print != null) {
_print = _ZoneFunction<PrintHandler>(this, print);
}
var fork = specification.fork;
if (fork != null) {
_fork = _ZoneFunction<ForkHandler>(this, fork);
}
var handleUncaughtError = specification.handleUncaughtError;
if (handleUncaughtError != null) {
_handleUncaughtError =
_ZoneFunction<HandleUncaughtErrorHandler>(this, handleUncaughtError);
}
}
首先,通过执行顺序来看,微任务调度器是比定时器更先执行的,那么微任务调度器的优先级更高,比较适合需要执行在事件队列之前的任务。