Flutter之Future原理解析

3,288 阅读11分钟

future是代表可能还没有发生的运算结果的对象。结果可能在未来的某个时间是可知的,因此被称为“future”。

简而言之,就是通过future来实现异步。正如isolate与进程类似,future也与线程类似。但也仅类似而已,毕竟future中还是与线程有很大区别的,比如线程既可执行IO密集型任务,也可执行计算密集型任务,而future仅能执行IO密集型任务。

Flutter中,Future是一个抽象类。可以自己来实现,也可以使用默认的实现类_Future,但基本上都是使用的默认实现。下面就来看_Future的实现原理。

1、_Future的状态

通过分析_Future的实现代码,可以发现它存在以下五种状态。

  1. _stateIncomplete:值为0,是初始状态,等待返回结果。在该状态下,_resultOrListeners是节点为_FutureListener对象的单链表的头节点。
  2. _statePendingComplete:值为1,等待完成。在调用_asyncComplete_asyncCompleteError方法时设置。_resultOrListeners是节点为_FutureListener对象的单链表的头节点。
  3. _stateChained:值为2。在该状态下,当前future与另外一个future连接在一起,另一个future的返回结果也变成当前future的的返回结果。当前future``的resultOrListeners指向另一个future
  4. _stateValue:值为4。该状态下future已经成功执行并带有返回值。
  5. _stateError:值为8。该状态下future已成功执行但返回了出错信息。

也就是无论如何使用_Future,它都是在上面这些状态间转化。在这里,我们不考虑出错的情况,所以也就忽略_stateError状态,那么就存在下面最基础的几种状态转化可能。

  1. _stateIncomplete->_stateValue,当直接调用Future的构造方法或者且其delayed时出现的情况。
  2. _stateIncomplete->_statePendingComplete->_stateValue,当调用Futurevalue方法时出现的情况。
  3. _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原理解析这篇文章。

再来看_Futurethen方法,它的代码实现如下。

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对象的状态来做不同的操作,主要有以下几种可能。

  1. _Future的状态值不大于_statePendingComplete,会将listener添加到链表中,等待异步执行完毕后再来遍历链表并执行该listener
  2. _Future的状态值是_stateChained时,并且当前_Future指向的_Future对象——source的状态值小于_stateValue时(也就是source的异步执行未完成)。则将listener添加到source对象所存在的链表中。
  3. _Future的状态值是_stateChained时,并且当前_Future指向的_Future对象——source的状态值大于等于_stateValue时(也就是source的异步执行已经完成)。则将source的返回值拷贝给当前_Future,并通过微任务来保证_propagateToListeners方法的尽快执行。
  4. _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

本示例与上节的示例稍有不同,本示例中调用了Futurevalue方法。而这个方法又有什么特点尼?下面就来看该方法的实现。

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);
  }

由于不考虑valueFuture的情况,所以在_asyncComplete方法中,先通过_setPendingComplete方法来将当前_Future对象的状态由_stateIncomplete改为_setPendingComplete,然后再通过微任务来实现异步。

再来看then方法,上节详细讲述过,这里就不多说明了。由于在本例中是通过微任务来实现异步的,所以在示例中就会先调用_Futurethen方法。此时两个_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

运行上面示例,可以发现f6f7的输出受f5的返回值影响,f5的输出及返回值受f4影响。也就是如果当前Future对象的返回值是一个Future对象,那么当前Future对象的后续执行则需要等待这个Future对象执行完毕。下面来看实现原理。

f1在异步执行时,会先调用f1then方法,这时候f1与通过f1then方法创建的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 {...}
  }
}

此时f1f2的关系如下。

在图中,f1_resultOrListeners不再指向链表的首节点,而是指向f2,而f2中包含从f1中移过来的链表及自身存在的链表。

以此类推,在等待f3的异步执行时,示例中各个Future对象的关系如下。

然后当f3异步执行完毕后,f3中链表会倒序执行。由于在执行listener节点时,也是会执行listenerresult指向的future对象,而result指向的future对象中又可以存在链表及result指向的一个新future对象,以此类推,就是Future的执行原理。当然在本示例中,result指向的future对象不存在链表。

细心一点可以发现,此时f1f2还是_stateChained状态,并没有转变为_stateValue状态。但如果再次调用f1f2then方法,就可以将f1f2的状态更新为_stateValue了,这就是上面说的四种状态转换情况中的第三情况。

3、总结

上面就是Future使用的最基础几种情况,虽然Future的使用场景很多,但基本上都是上面几种的各种组合。

最后再注意一点,如果_Future的状态是_stateValue或者_stateError。那么此时候再调用该_Futurethen方法,基本上就是通过微任务来执行回调方法了。关于微任务的实现原理,后面再来详细叙述。