future
是代表可能还没有发生的运算结果的对象。结果可能在未来的某个时间是可知的,因此被称为“future”。
简而言之,就是通过future
来实现异步。正如isolate
与进程类似,future
也与线程类似。但也仅类似而已,毕竟future
中还是与线程有很大区别的,比如线程既可执行IO密集型任务,也可执行计算密集型任务,而future
仅能执行IO密集型任务。
在Flutter
中,Future
是一个抽象类。可以自己来实现,也可以使用默认的实现类_Future
,但基本上都是使用的默认实现。下面就来看_Future
的实现原理。
1、_Future的状态
通过分析_Future
的实现代码,可以发现它存在以下五种状态。
_stateIncomplete
:值为0,是初始状态,等待返回结果。在该状态下,_resultOrListeners
是节点为_FutureListener
对象的单链表的头节点。_statePendingComplete
:值为1,等待完成。在调用_asyncComplete
、_asyncCompleteError
方法时设置。_resultOrListeners
是节点为_FutureListener
对象的单链表的头节点。_stateChained
:值为2。在该状态下,当前future
与另外一个future
连接在一起,另一个future
的返回结果也变成当前future
的的返回结果。当前future``的resultOrListeners
指向另一个future
。_stateValue
:值为4。该状态下future
已经成功执行并带有返回值。_stateError
:值为8。该状态下future
已成功执行但返回了出错信息。
也就是无论如何使用_Future
,它都是在上面这些状态间转化。在这里,我们不考虑出错的情况,所以也就忽略_stateError
状态,那么就存在下面最基础的几种状态转化可能。
- _stateIncomplete->_stateValue,当直接调用
Future
的构造方法或者且其delayed
时出现的情况。 - _stateIncomplete->_statePendingComplete->_stateValue,当调用
Future
的value
方法时出现的情况。 - _stateIncomplete->_stateChained->_stateValue,当
Future
的返回值时一个Future
对象时出现的情况。
后面就根据上面三种情况来分析_Future
的实现原理。
2、_stateIncomplete->_stateValue
来看一个示例,如下。
//example1
Future(() {
print("f1");
return "f2";
}).then((value) => print("value:$value"));
//或,example2
Future.delayed(Duration(milliseconds: 1000), () {
print("f1");
return "f2";
}).then((value) => print("value:$value"));
//或,...
...
//print
flutter: f1
flutter: value:f2
代码很简单明了。由于example2与example1的实现原理完全相同,所以这里以example1为例来分析其实现原理,实现代码如下。
abstract class Future<T> {
//创建一个_Future对象
factory Future(FutureOr<T> computation()) {
_Future<T> result = new _Future<T>();
Timer.run(() {
try {
//执行computation方法并把返回值传给_Future的_complete方法
result._complete(computation());
} catch (e, s) {
_completeWithErrorCallback(result, e, s);
}
});
return result;
}
}
代码很简单,就是通过Timer
来实现方法的异步执行并返回一个_Future
对象。关于Timer
是如何来实现异步的,可以去阅读Flutter之Timer原理解析这篇文章。
再来看_Future
的then
方法,它的代码实现如下。
class _Future<T> implements Future<T> {
var _resultOrListeners;
bool get _mayAddListener => _state <= _statePendingComplete;
//创建一个_FutureListener对象及_Future对象。但会把_FutureListener对象添加到链表中,_Future对象返回。
Future<R> then<R>(FutureOr<R> f(T value), {Function onError}) {
...
_Future<R> result = new _Future<R>();
_addListener(new _FutureListener<T, R>.then(result, f, onError));
return result;
}
//将listener添加到链表的具体实现
void _addListener(_FutureListener listener) {
if (_mayAddListener) {
//将listener添加到链表中
listener._nextListener = _resultOrListeners;
_resultOrListeners = listener;
} else {
if (_isChained) {
// Delegate listeners to chained source future.
// If the source is complete, instead copy its values and
// drop the chaining.
_Future source = _chainSource;
if (!source._isComplete) {
//将listener添加到source对象所在的链表中
source._addListener(listener);
return;
}
_cloneResult(source);
}
// Handle late listeners asynchronously.
_zone.scheduleMicrotask(() {
//处理调用then方法时传递的回调方法。
_propagateToListeners(this, listener);
});
}
}
}
在上面代码中,then
方法会创建一个新的_Future
对象——result
,然后把该对象及调用then
方法传递的回调方法一起赋给_FutureListener
对象——listener
,最后再通过_addListener
方法来处理listener
对象并在then
方法中返回result
。
再来看_addListener
方法,它会根据当前_Future
对象的状态来做不同的操作,主要有以下几种可能。
- 当
_Future
的状态值不大于_statePendingComplete
,会将listener
添加到链表中,等待异步执行完毕后再来遍历链表并执行该listener
。 - 当
_Future
的状态值是_stateChained
时,并且当前_Future
指向的_Future
对象——source
的状态值小于_stateValue
时(也就是source
的异步执行未完成)。则将listener
添加到source
对象所存在的链表中。 - 当
_Future
的状态值是_stateChained
时,并且当前_Future
指向的_Future
对象——source
的状态值大于等于_stateValue
时(也就是source
的异步执行已经完成)。则将source
的返回值拷贝给当前_Future
,并通过微任务来保证_propagateToListeners
方法的尽快执行。 - 当
_Future
的状态值是大于_stateChained
时。则通过微任务来保证_propagateToListeners
方法的尽快执行。
在上面示例中,由于满足状态值不大于_statePendingComplete
。所以此时会把listener
作为头节点添加到链表中,此时两个_Future
的关系如下。
当异步执行返回结果后,会调用_Future
的_complete
方法并把异步执行的结果作为参数传入。来看代码实现。
class _Future<T> implements Future<T> {
// This method is used by async/await.
//将_Future的状态修改为_stateValue
void _setValue(T value) {
assert(!_isComplete); // But may have a completion pending.
_state = _stateValue;
_resultOrListeners = value;
}
//从链表中获取尾节点
_FutureListener _removeListeners() {
// Reverse listeners before returning them, so the resulting list is in
// subscription order.
_FutureListener current = _resultOrListeners;
_resultOrListeners = null;
return _reverseListeners(current);
}
//链表反转
_FutureListener _reverseListeners(_FutureListener listeners) {
_FutureListener prev;
_FutureListener current = listeners;
while (current != null) {
_FutureListener next = current._nextListener;
current._nextListener = prev;
prev = current;
current = next;
}
return prev;
}
void _complete(FutureOr<T> value) {
//判断返回结果是否是Future或者其实现类
if (value is Future<T>) {
...
} else {
_FutureListener listeners = _removeListeners();
_setValue(value);
_propagateToListeners(this, listeners);
}
}
}
由于示例中的返回结果不是Future
及其实现类,所以这时候就从通过_removeListeners
方法来从链表中获取尾节点并执行_setValue
方法来修改当前_Future
对象的状态,此时_Future
的状态是_stateValue
。最后再调用_propagateToListeners
来遍历链表并执行所有listener
。
下面在来看_propagateToListeners
方法的实现,它是_Future
中非常重要的一个方法,在后面的状态转换中最终调用的也是该方法。
static void _propagateToListeners(_Future source, _FutureListener listeners) {
while (true) {
assert(source._isComplete);
bool hasError = source._hasError;
//结束轮询
if (listeners == null) {
if (hasError) {
//如果有错误就抛出
AsyncError asyncError = source._error;
source._zone
.handleUncaughtError(asyncError.error, asyncError.stackTrace);
}
return;
}
//通常情况下,futures仅有一个listener,如本示例。但如果有多个listener,将以递归的方式来处理所有listener。多listener的情况在后面会讲述到。
while (listeners._nextListener != null) {
_FutureListener listener = listeners;
listeners = listener._nextListener;
listener._nextListener = null;
_propagateToListeners(source, listener);
}
//listener是当前_Future对象中链表的尾节点
_FutureListener listener = listeners;
final sourceResult = source._resultOrListeners;
//设置listenerHasError与listenerValueOrError的初始状态
bool listenerHasError = hasError;
var listenerValueOrError = sourceResult;
//仅当遇到错误或者存在回调方法时,才执行下面的代码。由于有许多futures不存在回调方法,所以这些futures也就不执行下面的代码,这是一个重要的优化。
if (hasError || listener.handlesValue || listener.handlesComplete) {
...
// These callbacks are abstracted to isolate the try/catch blocks
// from the rest of the code to work around a V8 glass jaw.
void handleWhenCompleteCallback() {...}
//执行回调方法
void handleValueCallback() {
try {
listenerValueOrError = listener.handleValue(sourceResult);
} catch (e, s) {
listenerValueOrError = new AsyncError(e, s);
listenerHasError = true;
}
}
//执行错误回调
void handleError() {...}
if (listener.handlesComplete) {
handleWhenCompleteCallback();
} else if (!hasError) {
if (listener.handlesValue) {
//执行正确的回调方法
handleValueCallback();
}
} else {
if (listener.handlesError) {
//抛出错误
handleError();
}
}
// If we changed zone, oldZone will not be null.
if (oldZone != null) Zone._leave(oldZone);
//如果listener的返回值是future,则将该future与当前_Future关联起来并结束当前_Future的继续执行。
if (listenerValueOrError is Future) {
Future chainSource = listenerValueOrError;
// Shortcut if the chain-source is already completed. Just continue
// the loop.
_Future result = listener.result;
if (chainSource is _Future) {
if (chainSource._isComplete) {
listeners = result._removeListeners();
result._cloneResult(chainSource);
source = chainSource;
continue;
} else {
_chainCoreFuture(chainSource, result);
}
} else {
_chainForeignFuture(chainSource, result);
}
return;
}
}
//获取下一个即将执行的_Future对象
_Future result = listener.result;
//获取_Future对象的listeners,这个listeners也是尾节点
listeners = result._removeListeners();
if (!listenerHasError) {
//将result的状态修改为_stateValue
result._setValue(listenerValueOrError);
} else {
AsyncError asyncError = listenerValueOrError;
result._setErrorObject(asyncError);
}
// Prepare for next round.
source = result;
}
}
_propagateToListeners
方法中代码比较多,但主要就是以递归的方式来遍历_Future
中以_FutureListener
为节点的链表,并执行对应的回调。如果正确执行,那么回调方法的调用是在handleValueCallback
中,如果出现异常则在handleError
中来执行错误回调。
如果是上面的示例,那么最终也是在_propagateToListeners
方法中调用_setValue
方法来将_Future
的状态更新为_stateValue
。
下面再来看另外一种状态转换的情况。
2.2、_stateIncomplete->_statePendingComplete->_stateValue
来看一个示例,如下。
Future.value("f1").then((value) {
print("value:$value");
});
Future.value(() {
print("value:f1");
return "f2";
}).then((fun) {
print("value:${fun()}");
});
//print
flutter: value:f1
flutter: value:f1
flutter: value:f2
本示例与上节的示例稍有不同,本示例中调用了Future
的value
方法。而这个方法又有什么特点尼?下面就来看该方法的实现。
abstract class Future<T> {
//创建一个_Future对象
factory Future.value([FutureOr<T> value]) {
return new _Future<T>.immediate(value);
}
}
在该方法就是简单创建一个_Future
对象并调用该对象的immediate
方法,并没有通过Timer
来实现异步,那么再来看immediate
方法的实现。
_Future.immediate(FutureOr<T> result) : _zone = Zone.current {
_asyncComplete(result);
}
void _setPendingComplete() {
_state = _statePendingComplete;
}
void _asyncComplete(FutureOr<T> value) {
//暂不考虑value是Future的情况
if (value is Future<T>) {
_chainFuture(value);
return;
}
_setPendingComplete();
//通过微任务来执行_completeWithValue方法
_zone.scheduleMicrotask(() {
_completeWithValue(value);
});
}
void _completeWithValue(T value) {
_FutureListener listeners = _removeListeners();
_setValue(value);
_propagateToListeners(this, listeners);
}
由于不考虑value
是Future
的情况,所以在_asyncComplete
方法中,先通过_setPendingComplete
方法来将当前_Future
对象的状态由_stateIncomplete
改为_setPendingComplete
,然后再通过微任务来实现异步。
再来看then
方法,上节详细讲述过,这里就不多说明了。由于在本例中是通过微任务来实现异步的,所以在示例中就会先调用_Future
的then
方法。此时两个_Future
之间的关系如下。
当开始执行_completeWithValue
方法时,则会取出图中的listener
对象,然后将_Future1
的状态由_setPendingComplete
改为_stateValue
,最终再通过_propagateToListeners
方法来处理listener
。
关于_propagateToListeners
方法在上节已有了详细说明。
2.3、_stateIncomplete->_stateChained->_stateValue
仔细观察前两节的示例,会发现异步执行的结果都是一个非Future
对象。那么如果异步执行结果是一个Future
对象时,其实现原理是怎样的尼?
来看一个返回值是Future
对象的示例,如下。
Future.delayed(Duration(milliseconds: 500), () {//f1
print("f1");
return Future.delayed(Duration(milliseconds: 1000), () {//f2
print("f2");
return Future.delayed(Duration(milliseconds: 2000), () {//f3
print("f3");
return "f4";
}).then((value) {//f4
print("f5:$value");
});
}).then((value) {//f5
print("f6:$value");
});
}).then((value) {//f6
print("f7:$value");
return "f8";
}).then((value) {//f7
print("f9:$value");
});
//print
flutter: f1
flutter: f2
flutter: f3
flutter: f5:f4
flutter: f6:null
flutter: f7:null
flutter: f9:f8
运行上面示例,可以发现f6
、f7
的输出受f5
的返回值影响,f5
的输出及返回值受f4
影响。也就是如果当前Future
对象的返回值是一个Future
对象,那么当前Future
对象的后续执行则需要等待这个Future
对象执行完毕。下面来看实现原理。
当f1
在异步执行时,会先调用f1
的then
方法,这时候f1
与通过f1
的then
方法创建的Future
对象关系如下。
当f1
异步执行完毕后,会调用_Future
的_complete
方法,由于f1
的返回值是一个Future
对象,所以与返回值非_Future
对象的实现稍有不同。
class _Future<T> implements Future<T> {
void _complete(FutureOr<T> value) {
//判断返回结果是否是Future或者其实现类
if (value is Future<T>) {
if (value is _Future<T>) {
//如果Future的具体实现类是_Future
_chainCoreFuture(value, this);
} else {
//如果Future的具体实现类是自定义类
_chainForeignFuture(value, this);
}
} else {...}
}
}
这里先暂不考虑自定义类实现Future
的情况,所以就来看_chainCoreFuture
方法的实现。
class _Future<T> implements Future<T> {
//source是f1异步执行的返回值
static void _chainCoreFuture(_Future source, _Future target) {
assert(target._mayAddListener); // Not completed, not already chained.
while (source._isChained) {
source = source._chainSource;
}
if (source._isComplete) {
_FutureListener listeners = target._removeListeners();
target._cloneResult(source);
_propagateToListeners(target, listeners);
} else {
_FutureListener listeners = target._resultOrListeners;
target._setChained(source);
source._prependListeners(listeners);
}
}
}
由于此时f1
的状态还是_stateIncomplete
,所以就直接来判断source
的状态。如果source
的状态大于且等于_stateValue
,就直接把source
的返回值拷贝给f1
,并遍历f1
的链表来执行对应的回调方法;否则将f1
的状态更新为_stateChained
并通过_prependListeners
方法将f1
中的listener
链表移动到source
中,source
中原有的链表添加到尾部即可。
class _Future<T> implements Future<T> {
void _setChained(_Future source) {
_state = _stateChained;
_resultOrListeners = source;
}
//
void _prependListeners(_FutureListener listeners) {
if (listeners == null) return;
if (_mayAddListener) {
//source中已存在的链表
_FutureListener existingListeners = _resultOrListeners;
_resultOrListeners = listeners;
if (existingListeners != null) {
_FutureListener cursor = listeners;
//遍历从f1中移过来的链表
while (cursor._nextListener != null) {
cursor = cursor._nextListener;
}
//source中原有链表添加到新链表尾部
cursor._nextListener = existingListeners;
}
} else {...}
}
}
此时f1
与f2
的关系如下。
f1
的_resultOrListeners
不再指向链表的首节点,而是指向f2
,而f2
中包含从f1
中移过来的链表及自身存在的链表。
以此类推,在等待f3
的异步执行时,示例中各个Future
对象的关系如下。
然后当f3
异步执行完毕后,f3
中链表会倒序执行。由于在执行listener
节点时,也是会执行listener
中result
指向的future
对象,而result
指向的future
对象中又可以存在链表及result
指向的一个新future
对象,以此类推,就是Future
的执行原理。当然在本示例中,result
指向的future
对象不存在链表。
细心一点可以发现,此时f1
、f2
还是_stateChained
状态,并没有转变为_stateValue
状态。但如果再次调用f1
、f2
的then
方法,就可以将f1
、f2
的状态更新为_stateValue
了,这就是上面说的四种状态转换情况中的第三情况。
3、总结
上面就是Future
使用的最基础几种情况,虽然Future
的使用场景很多,但基本上都是上面几种的各种组合。
最后再注意一点,如果_Future
的状态是_stateValue
或者_stateError
。那么此时候再调用该_Future
的then
方法,基本上就是通过微任务来执行回调方法了。关于微任务的实现原理,后面再来详细叙述。