当前位置: 代码迷 >> 综合 >> Dart 异步模型
  详细解决方案

Dart 异步模型

热度:90   发布时间:2023-12-10 22:03:00.0

Dart汇总请点击这里

文章目录

      • Future
        • 创建Future
        • 注册回调
      • Future的特点
      • async 和 await
      • Future 原理
      • 使用 Future 控制任务调度

Future

Future模型是将异步请求和代理模式结合的产物。
Future类是对未来结果的一个代理,它返回的并不是被调用的任务的返回值。

//我的任务
void  myTask(){
    print("this is my task");
}void  main() {
    Future fut = new  Future(myTask);//根据我的任务创建Future对象
}

如上代码,Future类实例fut并不是函数myTask的返回值,它只是代理了myTask函数,封装了该任务的执行状态。换种理解方式就是,Future就是一个受你委托的委托人,你将未来要执行的任务交给他,你告知他任务类型是耗时任务,还是非耗时任务,然后分类放到事件循环中去,当任务完成后,它会第一时间执行回调方法告知你任务完成,或者会等到你委托给他的所有任务都完成了立马告知你。

创建Future

Future的几种创建方法

Future()
Future.microtask()
Future.sync()
Future.value()
Future.delayed()
Future.error()

其中sync是同步方法,任务会被立即执行

import  'dart:async';void  main() {
    print("main start");new  Future.sync((){
    print("sync task");
});new  Future((){
    print("async task");
});print("main stop");
}

运行结果:

main start
sync task
main stop
async task
注册回调

使用then注册回调

当Future中的任务完成后,我们往往需要一个回调,这个回调立即执行,不会被添加到事件队列。

import 'dart:async';void main() {
    print("main start");Future fut =new Future.value(18);// 使用then注册回调fut.then((res){
    print(res);});// 链式调用,可以跟多个then,注册多个回调new Future((){
    print("async task");}).then((res){
    print("async task complete");}).then((res){
    print("async task after");});print("main stop");
}

运行结果:

main start
main stop
18
async task
async task complete
async task after

除了then方法,还可以使用catchError来处理异常,如下

  new Future((){
    print("async task");}).then((res){
    print("async task complete");}).catchError((e){
    print(e);});

还可以使用静态方法wait 等待多个任务全部完成后回调。

import 'dart:async';void main() {
    print("main start");Future task1 = new Future((){
    print("task 1");return 1;});Future task2 = new Future((){
    print("task 2");return 2;});Future task3 = new Future((){
    print("task 3");return 3;});Future fut = Future.wait([task1, task2, task3]);fut.then((responses){
    print(responses);});print("main stop");
}

运行结果:

main start
main stop
task 1
task 2
task 3
[1, 2, 3]

如上,wait返回一个新的Future,当添加的所有Future完成时,在新的Future注册的回调将被执行。

Future的特点

  • Future中的then并没有创建新的Event丢到Event Queue中,而只是一个普通的Function Call,在FutureTask执行完后,立即开始执行

  • Future如果在then()调用之前Future就已经执行完毕了,那么会有一个任务被加入到microtask队列中。这个任务执行的就是被传入then的方法

  • Future只是创建了一个Event,将Event插入到了Event Queue的队尾

  • Future.value创建Task到microtask Queue中执行then传入的函数

  • Future.sync执行了它传入的函数之后,也会立即创建Task丢到microtask Queue中执行

  • Future.wait等待多个任务全部完成后回调。wait返回一个新的Future,当添加的所有Future完成时,在新的Future注册的回调将被执行。

  • Future.delayed在延时一定时间后向队列插入一个任务
    虽然可以预测任务执行的顺序,但是我们无法预测事件循环什么时候会从队列中提取任务。Dart事件处理系统基于单线程循环,而不是基于时基(tick,系统的相对时间单位)或者其他的时间度量。例如,当你创建一个延时1s的任务,1s后向事件队列添加一个任务,但在该任务之前的任务结束前,事件循环是不会处理这个任务的,也就是说该任务执行可能是大于1s的。

async 和 await

在Dart1.9中加入了async和await关键字,有了这两个关键字,我们可以更简洁的编写异步代码,而不需要调用Future相关的API。他们允许你像写同步代码一样写异步代码和不需要使用Future接口。

将 async 关键字作为方法声明的后缀时,具有如下意义

被修饰的方法会将一个 Future 对象作为返回值
该方法会同步执行其中的方法的代码直到第一个 await 关键字,然后它暂停该方法其他部分的执行;
一旦由 await 关键字引用的 Future 任务执行完成,await的下一行代码将立即执行。

// 导入io库,调用sleep函数
import 'dart:io';// 模拟耗时操作,调用sleep函数睡眠2秒
doTask() async{
    await sleep(const Duration(seconds:2));return "Ok";
}// 定义一个函数用于包装
test() async {
    var r = await doTask();print(r);
}void main(){
    print("main start");test();print("main end");
}

运行结果:

main start
main end
Ok

注意:需要注意,async 不是并行执行,它是遵循Dart 事件循环规则来执行的,它仅仅是一个语法糖,简化Future API的使用。

Future 原理

Dart 是事件驱动的体系结构,该结构基于具有单个事件循环两个队列的单线程执行模型。 Dart虽然提供调用堆栈。 但是它使用事件在生产者和消费者之间传输上下文。 事件循环由单个线程支持,因此根本不需要同步和锁定。
详细请参阅我的另一篇文章: Dart 事件循环

使用 Future 控制任务调度

将任务添加到MicroTask队列立即执行或将任务添加到Event队列空闲执行
详细请参阅我的另一篇文章:Dart 任务调度