future.dart阅读

Future

Future主要用于处理flutter中的异步输入事件,通过指定不同的初始化构造函数将异步任务转化为同步执行,提交到当前Isolate的microTask队列或eventTask队列
此外还提供了遍历的方法对future进行管理,错捕捉和拦截,future遍历,合并,同时还可以转换为更为灵活的Stream处理。在实际使用中应特殊注意异常的捕捉。它和Timer,Zone,Isolate密切相关.

Future执行顺序

根据执行效率来分,Future有3种创建方法,它们的优先级按如下先后顺序

1.Future.sync: 绝对同步指令,在当前函数栈中同步执行,优先级最高
2.Future.microTask/Future.value: 优先级相同, FIFO
3.Future(()=> { }): 异步创建,优先级最低

顺序补充说明,其实在理解上面 1,2,3之后就很容推导了
1.同优先级别按照先后顺序执行
2.同优先级内层嵌套Future优先级比外层底
3.Future.sync后接then,它的优先级降级为mircoTask级别,其它的Future创建then的优先级沿用创建时的优先级。

以下是测试代码:

void main() {
  print('start ....');
  
  Future.microtask(() => print('microtask0'));

  //通过Future.value的方式直接返回一个完成的Future,它直接插入到micoktask中
  Future.value('feature 0').then((value) => print('feature0->1')).then((value) => print('feature0->2'));

  //插入到当前Isolate EventLoop的EventQueue中
  Future(()=> print('feature 1'));
  
  //同步执行插入到当前Isolate EventLoop microTask队列中
  Future.microtask(() => print('microtask2'));

  //Future.sync为同步执行指令,和函数内的同步方法具有相同优先级
  final syncFuture = Future.sync(() => print('sync feature2'));
  syncFuture.then((value) => print('sync then feature3')).then((value) => print('sync then feature4'));
  Future.microtask(() => print('microtask4'));

  //顺序执行,插入到EventQueue中,执行顺序 `feature4`-> `feature5` -> feature6`,小于microTask
  final future4 = Future(() => print('feature4'));
  final microtask = Future.microtask(() => print('microtask5'));
  microtask.then((value) => print('microtask5-0'));

  future4.then((value) => print('feature5')).then((value) => print('feature6'));
  Future.microtask(() => print('microtask6'));
  
  //同步等待`feature7`和`feature8`执行完毕后再执行后面的`feature9`
  Future.wait([Future(() => print('feature7')), Future(() => print('feature8'))]).then((value) => print('feature 9'));
  
  //同层级的Future执行按先进先出的规则,嵌套的内层feature11,feature12的future要慢于外层`feature15`
  Future((){
     print('feature 10');
     Future.microtask(() => 'feature 10 mictask');
     Future(() => print('feature11')).then((value) => print('feature 12')); //内层feature11,feature12的future要慢于外层`feature15`
  }).then((value) => print('feature 13'));

  Future(() => print('feature 15'));

  Future.microtask(() => print('microtask15')).then((value) => print('microtask15 then'));

  Future.microtask(() => print('microtask16'));

  print('end ....');

//Log输出
/**
start ....
sync feature2
end ....
sync feature3
sync feature4
microtask1
microtask1 then
microtask2 then
microtask2
feature 1
feature4
feature5
feature6
feature7
feature8
feature 9
feature 10
  */
}

相关的类介绍

FutureOr<T> //用于描述一个Future对象,返回Future和Future的值

//T可以是任意的数据类型
Comparable (dart.core)
    BigInt (dart.core)  //大整数,hexacdemical literal
    DateTime (dart.core)
    Duration (dart.core)
    num (dart.core)
        double (dart.core)
        int (dart.core)
    String (dart.core)
Future (dart.async)
    _Future (dart.async)  //一个延迟计算的对象,它是一个抽象类
    SynchronousFuture (synchronous_future.dart) //提供一个同步执行的futrue
    TickerFuture (ticker.dart) //提供一个间隔执行的Future对象,动画vsyn信号回调专用
    DelegatingFuture (future.dart) //对`_Future`类的包装,简化用户调用接口
        ResultFuture (future.dart) //用于提供Future value,当future完成时可以同步获取到它对应的value

Future源码解读

abstract class Future<T> { 
  //在当前函数栈中同步创建一个带有数据的Future,访问时会被提交到microTaskQueue中
  _Future.value(T value) : this.zoneValue(value, Zone.current);
 
  //计算Future执行的命令,如果有嵌套则会异步全部执行完毕
  factory Future(FutureOr<T> computation()) {
    Timer.run(() { //通过Timer插入到EventLoop的EventQueue中,在CPU分配的时间片内执行本次任务
        result._complete(computation());//串联所有的Future,之后计算出最后的结果 

  //直接将计算任务添加到当前Isolate的microTaskQueue中
  factory Future.microtask(FutureOr<T> computation()) {
    scheduleMicrotask(() {
        //在本次调度的时间片内,完成计算操作
        result._complete(computation());
   
  //同步执行,直接采用当前函数分配的时间片执行
  factory Future.sync(FutureOr<T> computation()) { ...
      var result = computation();  ...
  
  //提交任务到microTask完成和value绑定
  @pragma("vm:entry-point")
  factory Future.value([FutureOr<T> value]) {
    return new _Future<T>.immediate(value); 
  //提交一个错误的值到 microTaskQueue中
  factory Future.error(Object error, [StackTrace stackTrace]) { ...
    return new _Future<T>.immediateError(error, stackTrace); 
  
  //提交一延迟执行的timer source到 EventLoop的EventQueue,
  factory Future.delayed(Duration duration, [FutureOr<T> computation()]) { ...
    new Timer(duration, () { 

  //合并多个Future事件,任何一个错误会导致整个list future抛出异常,通过指定cleanUp可以挽回部分成功的数据
  static Future<List<T>> wait<T>(Iterable<Future<T>> futures,
      {bool eagerError: false, void cleanUp(T successValue)}) { ...
    handleError(Object theError, StackTrace theStackTrace) {  
                cleanUp(value); ...
      //遍历合并数据
      for (var future in futures) {
        int pos = remaining;
        future.then((T value) { ...
              result._completeWithValue(values);
  

  /**
   * Returns the result of the first future in [futures] to complete.
   *
   * The returned future is completed with the result of the first
   * future in [futures] to report that it is complete,
   * whether it's with a value or an error.
   * The results of all the other futures are discarded.
   *
   * If [futures] is empty, or if none of its futures complete,
   * the returned future never completes.
   */
   //返回第一个future的执行结果
  static Future<T> any<T>(Iterable<Future<T>> futures) {
    var completer = new Completer<T>.sync();
    var onValue = (T value) {
      if (!completer.isCompleted) completer.complete(value);
    };
    var onError = (error, StackTrace stack) {
      if (!completer.isCompleted) completer.completeError(error, stack);
    };
    for (var future in futures) {
      future.then(onValue, onError: onError);
    }
    return completer.future;
  }
 
  //遍历执行 `elements`,可以支持同步和异步
  static Future forEach<T>(Iterable<T> elements, FutureOr action(T element)) { ...
  
  //配合forEach对elements进行遍历,并执行
  static Future doWhile(FutureOr<bool> action()) {
    _Future doneSignal = new _Future();
    void Function(bool) nextIteration;
    nextIteration = Zone.current.bindUnaryCallbackGuarded((bool keepGoing) {
      while (keepGoing) {
        FutureOr<bool> result;
        try {
          result = action(); //具体实现暴露给开发者,对数组类的元素进行转换 

  //callbak注册 订阅成功/失败/完成的几件
  Future<R> then<R>(FutureOr<R> onValue(T value), {Function onError});
  Future<T> catchError(Function onError, {bool test(Object error)});
  Future<T> whenComplete(FutureOr action());

  //转化为流事件
  Stream<T> asStream();

  //注册timeout事件,通常用于对突发异常进行retry操作
  Future<T> timeout(Duration timeLimit, {FutureOr<T> onTimeout()});
}

_Future

它是对Future的具体实现,对future输出的控制

class _Future<T> implements Future<T> { ...
  //状态标志位,代表了当前`_future`执行的状态
  static const int _stateIncomplete = 0;
  static const int _statePendingComplete = 1;
  static const int _stateChained = 2;
  static const int _stateValue = 4;
  static const int _stateError = 8;

  //初始化当前future的状态,当有订阅时开始变更
  int _state = _stateIncomplete;
  //当前Future执行的zone,用于提交then的microTask事件,绑定success和error事件
  final Zone _zone; 

  //存储当前的result或listeners,中间存储值
  @pragma("vm:entry-point")
  var _resultOrListeners;

  
  static List<Function> _continuationFunctions(_Future<Object> future) {
    List<Function> result = null;
    while (true) {
      //当pendding的时候才能添加future的listener
      if (future._mayAddListener) return result; ...
      //遍历执行listenr的绑定操作,Future每次listener操作完成之后返回一个新的Future用于串联future
        (result ??= <Function>[]).add(listener.handleValue);
        future = listener.result; 
  

  Future<R> then<R>(FutureOr<R> f(T value), {Function onError}) { ...
     //绑定成功的订阅事件到CurrentZone
      f = currentZone.registerUnaryCallback<FutureOr<R>, T>(f); 
      //选择性绑定onError事件到CurrentZone
      onError = _registerErrorHandler(onError, currentZone); 
    }
    //添加listener,每个listen持有了 then注册的回掉函数,并且在执行完成之后会返回一个新的Future,这也是为什么then能够连续串联好多个,由于`f`绑定的是同一个zone,所以他们执行在同一个zone下
    _Future<R> result = new _Future<R>();
    _addListener(new _FutureListener<T, R>.then(result, f, onError)); ...



  /// Registers a system created result and error continuation.
  ///
  /// Used by the implementation of `await` to listen to a future.
  /// The system created liseners are not registered in the zone,
  /// and the listener is marked as being from an `await`.
  /// This marker is used in [_continuationFunctions].
  //注册处一个系统回调事件,返回result由`await`关键字决定,`await future`就相当于执行这个方法
  Future<E> _thenAwait<E>(FutureOr<E> f(T value), Function onError) {
    _Future<E> result = new _Future<E>();
    _addListener(new _FutureListener<T, E>.thenAwait(result, f, onError));
    return result;
  }

  Future<T> catchError(Function onError, {bool test(error)}) {  
  Future<T> whenComplete(dynamic action()) { 
  
  //转换成一个future对象
  Stream<T> asStream() => new Stream<T>.fromFuture(this);
  
  //添加listener对象
  void _addListener(_FutureListener listener) {...
      _zone.scheduleMicrotask(() {  ... 

   //反转链表,确保先添加的先执行FIFO
  _FutureListener _reverseListeners(_FutureListener listeners) { ...

  //传递future用
  static void _chainForeignFuture(Future source, _Future target) { ...
  static void _chainCoreFuture(_Future source, _Future target) { ...
  
  void _complete(FutureOr<T> value) { 
  /**
   * Propagates the value/error of [source] to its [listeners], executing the
   * listeners' callbacks.
   */
   //在future完成时遍历listener发送事件给订阅者
  static void _propagateToListeners(_Future source, _FutureListener listeners) {
    while (true) { ...
      assert(source._isComplete);  ...
      while (listeners._nextListener != null) { ...
        void handleValueCallback() { ...
            listenerValueOrError = listener.handleValue(sourceResult);
        void handleError() {
              listenerValueOrError = listener.handleError(asyncError);
  
  //注册timeout订阅事件
  Future<T> timeout(Duration timeLimit, {FutureOr<T> onTimeout()}) { ...
      timer = new Timer(timeLimit, () { ...
          result._complete(zone.run(onTimeout)); ..
          result._completeError(e, s); 
    //自动实现了它的链式订阅
    this.then((T v) { ...
        result._completeWithValue(v);
        result._completeError(e, s); 

SynchronousFuture

从名字上看,它是一个同步执行的future

class SynchronousFuture<T> implements Future<T> { ...
  @override
  Future<T> catchError(Function onError, { bool test(Object error) }) => Completer<T>().future;
  
  //f函数执行执行,没有绑定zone的复杂流程,Future.sync
  @override
  Future<E> then<E>(FutureOr<E> f(T value), { Function onError }) {...
    final dynamic result = f(_value);   
  @override
  Future<T> whenComplete(FutureOr<dynamic> action()) { ...
}

DelegatingFuture

代理Future,ResultFuture继承于它,提供了 Future直接访问reuslt的能力,具体实现在Result类中

class DelegatingFuture<T> implements Future<T> { ...
  DelegatingFuture(this._future);
  @override
  Stream<T> asStream() => _future.asStream(); ...
  @override
  Future<T> catchError(Function onError, {bool Function(Object error) test}) =>  ...
  @override
  Future<S> then<S>(FutureOr<S> Function(T) onValue, {Function onError}) => ...
  @override
  Future<T> whenComplete(FutureOr Function() action) => ...
  @override
  Future<T> timeout(Duration timeLimit, {FutureOr<T> Function() onTimeout})  ...

class ResultFuture<T> extends DelegatingFuture<T> { 
  bool get isComplete => result != null; 
  Result<T> get result => _result;
  Result<T> _result;

  ResultFuture(Future<T> future) : super(future) {
    Result.capture(future).then((result) {
      _result = result;
    });
  }
}

abstract class Result<T> { ....
  final T value; ...
  static Future<Result<T>> capture<T>(Future<T> future) {
    return future.then((value) => ValueResult(value),
        onError: (error, StackTrace stackTrace) =>
            ErrorResult(error, stackTrace));
  }

与FutureBuilder的结合使用

  • FutureBuilder用于实现一个异步构建的widget,根据当前异步事件执行的状态显示不同的widget,在实际工作中会经常用到,它的本质就是将 需要传递的数据分成不同的的阶段获取,然后再拿到每个阶段的数据后调用setState去触发Widget的build,实际的widget封装在它的构造然后中,

  • 下面是一个简易的FutureBuider,只是为了理解其中的运作流程,具体细节暂时忽略

//提供构建的四个阶段的数据,根据实际需要还可以定义得更多。
enum FutureStatus {
  initial,
  done,
  error,
  pending,
}
//包装状态和数据,用于构建每个阶段的widget
class FutureSnapshot {
  dynamic data;
  FutureStatus status;
  FutureSnapshot({this.data, this.status});
}

typedef WidgetBuilder = Widget Function(BuildContext, FutureSnapshot);

class CustomFutureBuilder extends StatefulWidget {
  final Future future;
  final WidgetBuilder builder;
  CustomFutureBuilder({this.future, this.builder});
  @override
  CustomFutureBuilderState createState() => CustomFutureBuilderState();
}

class CustomFutureBuilderState extends State<CustomFutureBuilder> {
  FutureSnapshot snapshot;

  @override
  Widget build(BuildContext context) => widget.builder(context, snapshot);
  @override
  void initState() {
    super.initState();
    snapshot = FutureSnapshot(status: FutureStatus.initial, data: null); //初始化阶段,
    subscribe();
  }

  void subscribe() {
    widget.future.then((value) {
      setState(() {
        snapshot = FutureSnapshot(status: FutureStatus.initial, data: value); //数据加载成功阶段
      });
    }, onError: (error, stackTrace) {
      setState(() {
        snapshot = FutureSnapshot(
            status: FutureStatus.initial,
            data: FlutterErrorDetails(exception: error, stack: stackTrace)); //数据加载失败阶段
      });
    });
    snapshot = FutureSnapshot(
        status: FutureStatus.initial, data: FlutterErrorDetails()); //等待阶段
  }
}

class CustomFutureBuilderDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return CustomFutureBuilder(     //具体使用.
        future: Future.value('xxxxx'),
        builder: (contxt, snapShot) {
          switch (snapShot.status) {
            case FutureStatus.error:
              return Text('error');
            case FutureStatus.initial:
              return Text('initial');
            case FutureStatus.done:
              return Text('done');
            case FutureStatus.pending:
              return CircularProgressIndicator();
          }
          return Container();
        });
  }
}

上面的例子主要介绍了FutureBuilder的一些基本功能,在实际的使用中,还需要考虑到widget的刷新,future的变化,如何去解除订阅,重新初始化构建树,下面是标准的futurebuilder实现。

class _FutureBuilderState<T> extends State<FutureBuilder<T>> {
 
  Object _activeCallbackIdentity; //增加了Callback标志符,来控制future的同步
  AsyncSnapshot<T> _snapshot; //同上面的FutureSnapShot一样,包装状态和值

  @override
  void initState() {
    super.initState();
    _snapshot = AsyncSnapshot<T>.withData(ConnectionState.none, widget.initialData); //初始化阶段状态和值
    _subscribe();  //订阅Future
  }

  @override
  void didUpdateWidget(FutureBuilder<T> oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.future != widget.future) {  //视图更新后对future解绑操作,重新订阅新的future
      if (_activeCallbackIdentity != null) {
        _unsubscribe();
        _snapshot = _snapshot.inState(ConnectionState.none); //重制阶段状态和值
      }
      _subscribe();
    }
  }

  @override
  Widget build(BuildContext context) => widget.builder(context, _snapshot);

  @override
  void dispose() {
    _unsubscribe();
    super.dispose();
  }

  void _subscribe() {
    if (widget.future != null) {
      final Object callbackIdentity = Object();
      _activeCallbackIdentity = callbackIdentity;
      widget.future.then<void>((T data) {
        if (_activeCallbackIdentity == callbackIdentity) {
          setState(() {
            _snapshot = AsyncSnapshot<T>.withData(ConnectionState.done, data); //完成阶段状态值
          });
        }
      }, onError: (Object error) {
        if (_activeCallbackIdentity == callbackIdentity) {
          setState(() {
            _snapshot = AsyncSnapshot<T>.withError(ConnectionState.done, error); //错误阶段状态值
          });
        }
      });
      _snapshot = _snapshot.inState(ConnectionState.waiting); //等待阶段状态值
    }
  }

  void _unsubscribe() {
    _activeCallbackIdentity = null;  //控制future和build同步的标志位,类似信号量(不过flutter ui线程为单线程)避免future执行时widget已经被移除了.
  }
}

StreamBuilder与Future应用

和Future的设计方式基本一致,只不过他的状态多一点点,数据源是持续的,不想future的数据是单次的,StreamBuilder继承了_StreamBuilderBase,_StreamBuilderBase用来管理stream流的订阅和更新,StreamBuilder则更多的是用来实现暴露给用户的接口,状态值的变化,Widget的builder实现.

相比较FutureBuilder主要差异主要在这里,状态值多一些.

class _StreamBuilderBaseState<T, S> extends State<StreamBuilderBase<T, S>> ...
void _subscribe() {
    if (widget.stream != null) {
      _subscription = widget.stream.listen((T data) {
        setState(() {
          _summary = widget.afterData(_summary, data);
        });
      }, onError: (Object error) {
        setState(() {
          _summary = widget.afterError(_summary, error);
        });
      }, onDone: () {
        setState(() {
          _summary = widget.afterDone(_summary);
        });
      });
      _summary = widget.afterConnected(_summary);
    }
  }

通常而言,处理简单的网络回调请求一般用FutureBuider就能满组需求了,如果是涉及到持续的数据订阅如蓝牙数据,定位信息等,可以采用StreamBuilder.在使用过程中需要特别注意 异步Future/Stream对象变更后,他所构建的wiget的作用域问题.因为widget切换会导致他们所依赖的 InheritedWidget被移除, 如果是项目中使用了Bloc应特别注意。

小结

Future是为适配Isolate中的 microTask和eventTask2而涉及,包含了常规的数据订阅,输入输出,异常捕捉, 多个异步数据合并,通过异步数据顺序执行,并且提供了便利的Completer对future的使用进行解耦操作,基于Future的基本功能, 同时也为Stream流和RxData的封装奠定了基石。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容

  • Dart是基于事件循环机制的单线程模型 一条执行线上,同时且只能执行一个任务(事件),其他任务都必须在后面排队等待...
    Hankkinn阅读 918评论 0 1
  • 语雀 什么是 Future Future是Dart中提供的一个抽象类、泛型类,它用于封装一段在将来会被执行的代码逻...
    态度哥阅读 8,957评论 0 7
  • Dart 部分 其实学习过 JavaScript 或者 Java/Kotlin 的人,在学习 Dart 上几乎是没...
    Android高级工程师阅读 1,626评论 0 10
  • 由于dart是一种单线程的语言,在编写dart代码时对于耗时操作的处理要使用异步来进行。dart中自带有futur...
    蓝色的风阅读 1,368评论 0 2
  • 黑色的海岛上悬着一轮又大又圆的明月,毫不嫌弃地把温柔的月色照在这寸草不生的小岛上。一个少年白衣白发,悠闲自如地倚坐...
    小水Vivian阅读 3,093评论 1 5