Dart基础7-异步

java中用thread来支持异步操作,而dart中用的是Future

Future

表示在将来某时获取一个值的方式,本质是等待其他队列完成

基础使用

//执行打印顺序是先a再b
main(){
  Future f = Future(() => print("b"));
  print("a");
}

我们在Future中使用延迟操作并不影响main线程的其他方法执行,并不会阻塞线程

关键字 async 和 await

main(){
  getName1();
  getName2();
}

Future<void> getName1() async {
  Future(()=>print("===1===")); 
  await getStr1(); //遇到第一个await表达式执行暂停,返回future对象,await表达式执行完成后继续执行
  await Future(()=>print("===2===")); //await表达式可以使用多次
  print('getName1');
}

getStr1() {
  print('getStr1');
}

getName2() {
  print('getName2');
}

打印结果为:

getStr1
getName2
===1===
===2===
getName1

await关键字,会先执行函数,然后返回一个Future对象
await必须在async修饰的函数中才能使用
如果函数没有返回一个有用的值,那么将其返回Future<void>类型

错误处理

main(){
  Future(() => 0) //  异步任务的函数
      .then((m) => "a$m") //   任务执行完后的子任务
      .then((m) => print('显示: $m')) //  其中m为上个任务执行完后的返回的结果
      .then((_) => Future.error('error'))  //返回错误,上一步未返回m,此步的参数无意义
      .then((_) => print('我并不执行'))
      .whenComplete(() => print('whenComplete1')) //不是最后执行whenComplete,通常放到最后回调
      .catchError((e) => print('catchError:' + e), test: (Object o) {
        print('test:' + o);
        //return true; //返回true,会被catchError捕获
        return false; //返回false,继续抛出错误,会被下一个catchError捕获,自己不做处理
      })
      .catchError((e) => print(e));//如果不写test默认实现一个返回true的test方法
}

打印结果

显示: a0
whenComplete1
test:error
error

whenComplete和then区别

  1. whenComplete在上一步报错后仍会执行,而then不会
  2. whenComplete的闭包函数是无参的,而then的需要传递一个参数

scheduleMicrotask

main(){
  Future(() => print("f")); //3. 最后执行
  scheduleMicrotask(() => print('s'));  //2. 次之 
  print("a"); // 1. 优先执行
}
调用顺序

这里会建立2个队列,Microtask队列和event队列,Microtask优先于event队列,当Microtask全部执行完后才会执行event

嵌套使用的调用顺序

main(){
  Future(() => print('s1'))
      .then((_) => Future(() => print('s2')))
      .then((_) => print('s3'));
  
  Future(() => print('s4')).then((_) {
    print('s5');
    scheduleMicrotask(() => print('s6'));
  }).then((_) => print('s7'));
}

打印顺序是:

s1
s4
s5
s7
s6
s2
s3

在s1之后的then又创建了一个Future,Future需要当前Zone的Future全部执行完,才会执行下一个。而s3需要在s2执行完毕后才执行,因为需要等待s2那步返回的参数
如果将第一个改为:

//无返回值
Future(() => print('s1'))
      .then((_) { Future(() => print('s2'));})
      .then((_) => print('s3'));

打印结果

s1
s3
s4
s5
s7
s6
s2

深入分析

内部其实使用的是一个定时任务

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

我们做一个测试:

main(){
  Timer.run(() {
    print("c");   // 3
  });
  scheduleMicrotask(() => print('b')); // 2
  print("a");  // 1
}

接着分析一下then:

Future<R> then<R>(FutureOr<R> f(T value), {Function onError}) {
    Zone currentZone = Zone.current;
    if (!identical(currentZone, _rootZone)) {
      f = currentZone.registerUnaryCallback<FutureOr<R>, T>(f);
      if (onError != null) {
        onError = _registerErrorHandler(onError, currentZone);
      }
    }
    return _thenNoZoneRegistration<R>(f, onError);
  }

并未做什么处理,直接追踪 _thenNoZoneRegistration

Future<E> _thenNoZoneRegistration<E>(
      FutureOr<E> f(T value), Function onError) {
    _Future<E> result = new _Future<E>();
    _addListener(new _FutureListener<T, E>.then(result, f, onError));
    return result;
  }

找到了一个增加监听器的方法,进入查看

void _addListener(_FutureListener listener) {
    assert(listener._nextListener == null);
    if (_mayAddListener) {
      listener._nextListener = _resultOrListeners;
      _resultOrListeners = listener;
    } else {
      if (_isChained) {
        _Future source = _chainSource;
        if (!source._isComplete) {
          source._addListener(listener);
          return;
        }
        _cloneResult(source);
      }
      assert(_isComplete);
      //执行
      _zone.scheduleMicrotask(() {
        _propagateToListeners(this, listener);
      });
    }
  }

一大段处理后,最终来到scheduleMicrotask方法

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

内部其实还是使用的scheduleMicrotask,创建一个Microtask队列

到此,我们来模拟一下:

main(){
  Timer.run(() {
    print("b");   // 2
    scheduleMicrotask(() => print('c')); // 3
    scheduleMicrotask(() => print('d')); // 4
  });
  Timer.run(() {
    print("e");   // 5
  });
  print("a");  // 1
}

也简单的实现了then的效果

Isolate

为了保持你app的可响应性,大计算量的任务放入额外的isolate中

它是类似于线程(thread)但不共享内存的独立运行的worker,是一个独立的Dart程序执行环境。默认环境main就是一个isolate

官方使用例子:

import 'dart:async';
import 'dart:isolate';

main() async {
  var receivePort = new ReceivePort();
  await Isolate.spawn(echo, receivePort.sendPort);

  //'echo'发送的第一个message,是它的SendPort
  //first 是 echo 线程的消息入口
  var sendPort = await receivePort.first;

  var msg = await sendReceive(sendPort, "foo");
  print('received $msg');
  msg = await sendReceive(sendPort, "bar");
  print('received $msg');
}

/// 新isolate的入口函数
echo(SendPort sendPort) async {
  // 实例化一个ReceivePort 打开接收端口以接收消息
  var port = new ReceivePort();

  // 把它的sendPort发送给宿主isolate,以便宿主可以给它发送消息
  sendPort.send(port.sendPort);

  // 监听循环接收消息
  await for (var msg in port) {
    var data = msg[0];
    SendPort replyTo = msg[1];
    replyTo.send(data);
    if (data == "bar") port.close();
  }
}

/// 对某个port发送消息,并接收结果
Future sendReceive(SendPort port, msg) {
  ReceivePort response = new ReceivePort();
  port.send([msg, response.sendPort]);
  return response.first;
}

生成器

当需要延迟地生成一个值序列时,请考虑使用生成器函数

//同步生成器: 使用sync*,返回的是Iterable对象
Iterable<int> getSyncGenerator(int n) sync* {
  print('start');
  int k = n;
  while (k > 0) {
    //yield会返回moveNext为true,并等待 moveNext 指令
    yield k--;
  }
  print('end');
}

//异步生成器: 使用async*,返回的是Stream对象
Stream<int> getAsyncGenerator(int n) async* {
  print('start');
  int k = 0;
  while (k < n) {
    //yield不用暂停,数据以流的方式一次性推送,通过StreamSubscription进行控制
    yield k++;
  }
  print('end');
}

//递归生成器:使用yield*
Iterable<int> getSyncRecursiveGenerator(int n) sync* {
  if (n > 0) {
    yield n;
    yield* getSyncRecursiveGenerator(n - 1);
  }
}

//异步递归生成器
Stream<int> getAsyncRecursiveGenerator(int n) async* {
  if (n > 0) {
    yield n;
    yield* getAsyncRecursiveGenerator(n - 1);
  }
}

递归生成器使用方法是一样的

main() {
   //同步生成器
  //调用getSyncGenerator立即返回Iterable
  var it = getSyncGenerator(5).iterator;
//  调用moveNext方法时getSyncGenerator才开始执行
  while (it.moveNext()) {
    print(it.current);
  }

  //异步生成器
  //调用getAsyncGenerator立即返回Stream,只有执行了listen,函数才会开始执行
 // getAsyncGenerator(5).listen((value) => print(value));
  StreamSubscription subscription = getAsyncGenerator(5).listen(null);
  subscription.onData((value) {
    print(value);
    if (value >= 2) {
      subscription.pause(); //可以使用StreamSubscription对象对数据流进行控制
    }
  });
 print('over');
}

总结:

  1. Dart事件循环执行两个队列里的事件:event队列和microtask队列
  2. 事件循环会优先清空microtask队列,然后才会去处理event队列。当两个队列都清空后,dart就会退出

详细可参见:https://webdev.dartlang.org/articles/performance/event-loop

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

推荐阅读更多精彩内容