Dart 基础之Future使用

什么是future

future类似android中的handler,表示稍后做的任务
使用如下:

 Future((){
      print('future do..');
      return '1';
    }).then(print);
print('main end');

可以看到main end先打印,然后打印future里面的任务,最后then打印结果

main end
future do..
1

future 异常捕获

future的异常处理有两方法catchError和onError,

catchError(Function onError, {bool test(Object error)?})
onError<E extends Object>(
  FutureOr<T> handleError(E error, StackTrace stackTrace),
  {bool test(E error)?})

如果发生异常了,那么then方法就不会被调用,但是whenComplete方法最终也会被调用,类似于Java里面的finally。
异常示例代码如下:

 Future((){
       throw Exception('this is error');
    }).then((v){
      print(v);
    })
        .whenComplete(() => print('done'));
    print('main end')

输出异常

main start
main end
done
Unhandled exception:
Exception: this is error

加上catchError后,

Future((){
       throw Exception('this is error');
    }).then((v){
      print(v);
    })
        .catchError((e,stackTrace){
      print('catch Error: $e');
    })
        .whenComplete(() => print('done'));
    print('main end');

输出如下,可以看到catchError捕获到了异常,参数e为异常对象,参数stackTrace为当前堆栈信息

main start
main end
catch Error: Exception: this is error
done

catchError方法还有个可选参数 {bool test(Object error)?},表示如果我只想捕获某种类型的异常,
代码如下,表示我只捕获FileSystemException类型异常

  Future((){
       throw Exception('this is error');
    }).then((v){
      print(v);
    }).catchError((e){
    print('catch Error: $e');
    },test: (e)=>e is FileSystemException)
        .whenComplete(() => print('done'));
    print('main end');

输出异常如下,异常没有捕获到

main start
main end
Unhandled exception:
Exception: this is error
done

onError是Future的扩展方法,内部也是调用的catchError方法

Future<T> onError<E extends Object>(
      FutureOr<T> handleError(E error, StackTrace stackTrace),
      {bool test(E error)?}) {
    // There are various ways to optimize this to avoid the double is E/as E
    // type check, but for now we are not optimizing the error path.
    return this.catchError(
        (Object error, StackTrace stackTrace) =>
            handleError(error as E, stackTrace),
        test: (Object error) => error is E && (test == null || test(error)));
  }

构造方法microtask,sync同Future({})使用相同,区别就是Future把任务放在事件队列,microtask把任务放在微任务队列

  Future((){
      print('future do..');
      return '1';
    }).then(print);
    Future.microtask((){
      print('microtask do');
      return '4';
    } ).then(print);
    Future.sync(() {
      print('sync do');
      return '5';}).then(print);

    print('main end');

输出

main start
sync do
main end
2
microtask do
4
5
future do..
1

Process finished with exit code 0

等待超时timeout

timeout(Duration timeLimit, {FutureOr<T> onTimeout()?})

设置超时时间,如果任务超时了,如果onTimeout参数有设置,调用onTimeout,如果onTimeout参数没设置,直接抛出TimeoutException异常

 Future(()async{
      await Future.delayed(Duration(seconds: 2));
      return 'a';
    }).timeout(Duration(seconds: 1),onTimeout: ()=>'time out').then(print).whenComplete(() => print('done'));

输出

time out
done

构造方法delay:表示延迟任务

如下表示延迟1s后执行return

 Future.delayed(Duration(seconds: 1),(){
      return '3';
    });

构造方法error,抛出一个异常

    print('main start');
    var v = await getComplete(1,0);
    print('main end');

  Future<int> getComplete(int a,int b){
    if(b == 0){
      return Future.error(Exception('b cannot 0'));
    }
    return Future.value(a~/b);
  }

输出如下,可以看出程序非正常退出了,在await那行就抛出了异常。这就要求调用getComplete方法的地方一定要处理异常

main start
Unhandled exception:
Exception: b canot 0

Process finished with exit code 255

静态方法wait,等待多个future结果

Future<List<T>> wait<T>(Iterable<Future<T>> futures,
  {bool eagerError = false, void cleanUp(T successValue)?}
 int start = DateTime.now().millisecondsSinceEpoch;
    List<dynamic> value = await Future.wait<dynamic>([
      delayedNumber(1),
      delayedString("a"),
      delayedNumber(1),
      delayedString('b'),
    ]);
    int cost = DateTime.now().millisecondsSinceEpoch-start;
    print("cost:${cost/1000} s, value:$value"); 

//模拟耗时,延迟3秒
Future<int> delayedNumber(int num) async {
    await Future.delayed(const Duration(seconds: 3));
    return 2;
  }
//模拟耗时,延迟2秒
  Future<String> delayedString(String value) async {
    await Future.delayed(const Duration(seconds: 2));
    return value;
  }

输出结果如下,可以看出最终耗时并不是几个future的总和,而是最大的耗时任务,相当于并行处理

cost:3.025 s, value:[2, a, 2, b]

静态方法any,执行多个future,只要有一个完成就返回结果

同样是上述代码,把wait换成any,返回值就不是list了,因为只有一个结果会返回

 int start = DateTime.now().millisecondsSinceEpoch;
    dynamic value = await Future.any<dynamic>([
      delayedNumber(1),
      delayedString("a"),
      delayedNumber(1),
      delayedString('b'),
    ]);
    int cost = DateTime.now().millisecondsSinceEpoch-start;
    print("cost:${cost/1000} s, value:$value"); 

输出结果,返回的用时最小的a

cost:2.019 s, value:a

静态方法forEach,对集合每个元素执行action操作

forEach<T>(Iterable<T> elements, FutureOr action(T element))

同时这个方法的调用then是拿不到数据的
示例代码如下

 print('main start');
Future.forEach([1,2,3,4], (element) {
      print(element);
      return 'a';
    }).then((value) => print(value));
    print('main end');

输出,可以看出,和正常的集合遍历没啥区别,而且是立马执行的

main start
1
2
3
4
main end
null

修改代码action返回值为future,其他不变,

Future.forEach([1,2,3,4], (element) {
      print(element);
      return Future.value('a');
    }).then((value) => print(value));

输出如下,可以看到除了第一个元素,后面的元素在稍后执行

main start
1
main end
2
3
4
null

静态方法doWhile:返回为true时会一直重复,直到返回false

适合用在有轮询情况的业务,没有达到条件就一直轮询
示例如下,当value为3时才执行then语句

 Future task = Future.doWhile(()async{
      await Future.delayed(const Duration(seconds: 1));
      value++;
      if (value == 3) {
        return false;
      }
      return true;
    });
task.then((_){
      print('Finished with $value');
    });

输出

Finished with 3

Completer

如果我们写的一个方法A返回的是Future类型,,但是我们A方法里面调用了B方法,B方法是个异步方法,但是B方法返回是利用回调返回,
这种场景比较常见我们调用其他人的异步方法时,如果这个异步方法返回的是Future,那我们可以直接用await获取异步结果,但是如果不是,这个时候如果我们还想用Future返回,就可以用Completer了

例子如下,call方法通过callback回调结果,

 Future<int> testCompleter(){
    Completer<int> c = Completer();
   call((d){
      c.complete(d);
    });
    return c.future;
  }
  void call(Function callback){
    Future.delayed(Duration(seconds: 1),(){
       callback(123);
    });
  }

    print('main start');
    testCompleter().then(print);
    print('main end');

输出

main start
main end
123

Process finished with exit code 0
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容