今天我们来学Dart中的异步编程和Future

异步编程

​ image-20260418103656415

这里我们简单描述一下进程和线程

进程和线程

进程就是正在运行中的程序,因为电脑上的软件是存在在磁盘上的,即以文件的形式存储的,也就是我们熟悉的文件夹,包括手机平板也是同样的,当我们点开一个软件时,首先这个软件会被加载到内存并获得系统资源,然后开始执行

你使用ctrl + alt +del 打开你的资源管理器就明白了(话说我后台怎么这么多程序,难道是开机自启动? 难怪每次开机这么慢)

​ image-20260418104835840

程序运行会占用内存,每个进程之间内存隔离互不影响,比如你终止了哔哩哔哩的进程,不会影响其他软件的使用

​ image-20260418121642703

至于线程,就是程序内部的执行路线,单个进程里有至少一个线程,以浏览器为例

Chrome(进程)

├── 线程1:渲染页面

├── 线程2:网络下载

├── 线程3:执行 JavaScript

└── 线程4:播放音频

即进程给程序分配资源,线程负责执行程序

多线程就是多个线程同时进行执行任务,效率更高,但是单线程就是排队执行任务,上一个任务执行完毕才会轮到下一个

Future

​ image-20260418163623676

正常情况下是这样的,这里用了回调函数

​ image-20260418164722903

DART已复制
void main(List<String> args) {
  Future f = Future(() {
    return "baka";
    throw Exception();//throw抛出异常
  });

  //then 中接收成功状态
  f.then((value) {
    print(value);
  });
  //catchError 中接收失败状态
  f.catchError((err) {
    print("出~错~了 ! zako~ zako~ zako~");
  });
}

异常情况下是这样的

​ image-20260418164823601

DART已复制
void main(List<String> args) {
  Future f = Future(() {
    //return "baka";
    throw Exception();//throw 抛出异常
  });

  //then 中接收成功状态
  f.then((value) {
    print(value);
  });
  //catchError 中接收失败状态
  f.catchError((err) {
    print("出~错~了 ! zako~ zako~ zako~");
  });
}

Flutter的链式调用

上一个 then 返回对象,会在下一个 then 中接收

DART已复制
void main(List<String> args) {
  Future f = Future(() {
    return "baka_00";
    //throw Exception;
  });

  //then 中接收成功状态
  f
      .then((value) {
        return Future(() => "baka_01");
      })
      .then((value) {
        return Future(() => "$value----baka_02");
      })
      .then((value) {
        return Future(() => "$value----baka_03");
      })
      .then((value) {
        print(value);
      })
      .catchError((err) {
        print("出~错~了 ! zako~ zako~ zako~");
      });
}
DART已复制
void main() {
  Future.value(10)
      .then((value) {
        print("第1步收到:$value");

        // 返回一个新值(会传给下一个 then)
        return value + 5;
      })
      .then((value) {
        print("第2步收到:$value");

        // 再返回一个值
        return value * 2;
      })
      .then((value) {
        print("第3步收到:$value");
      })
      .catchError((error) {
        print("发生错误:$error");
      });
}

async和await

​ image-20260418181659653

你可以发现在函数的参数括号后面有async 指的是 asynchronous(异步),代表当前函数是异步的

关键字 作用
async 声明函数是异步
await 等待异步结果
DART已复制
Future<String> getName() async {
  return "Tom";
}

void main() async {
  var name = await getName();
  print(name);
}
DART已复制
Future<String> fetchData() async {
  await Future.delayed(Duration(seconds: 2)); //延迟两秒钟,和unity中的协程非常相似
  return "数据加载完成";
}

void main() async {
  print("开始请求");

  var data = await fetchData();

  print(data);
  print("结束");
}

这里你可以注意到一行代码 Future.delayed(Duration(seconds: 2));

这里其实完整格式是

(new) Future<String>.delayed(Duration duration, [FutureOr<String> Function()? computation])

其中第一个参数Duration duration是指延迟时间例如延迟一秒钟Duration(seconds: 1)

而第二个参数是可选的,即延迟时间之后的返回值,通常为 匿名函数()=>{ return 返回值 },这里的返回值必须和泛型里规定的一致

DART已复制
Future<String> getUser() async {
  return Future.delayed(Duration(seconds: 1), () {
    return "Tom";
  });
}

Future<String> getOrder(String user) async {
  return Future.delayed(Duration(seconds: 1), () {
    return "$user 的订单:iPhone";
  });
}

Future<String> getDetail(String order) async {
  return Future.delayed(Duration(seconds: 1), () {
    return "$order(128GB)";
  });
}

void main() async {

  print("开始请求");

  var user = await getUser();
  print("用户:$user");

  var order = await getOrder(user);
  print("订单:$order");

  var detail = await getDetail(order);
  print("详情:$detail");

  print("结束");

}

try catch

这个和C#里的很像,C#里也有try catch函数,这里 try 指的是 尝试(try block) 而catch指的是 捕获(catch exception)

DART已复制
void main() {
  try {
    int a = 10 ~/ 0; // 整数除零,会报错

    print(a);
  } catch (e) {
    print("出错了:$e");
  }
}

在异步里就是

DART已复制
Future<String> getData() async {
  throw Exception("网络挂了");
}

void main() async {
  try {
    var data = await getData();

    print(data);
  } catch (e) {
    print("捕获到错误:$e");
  }
}

其实和if lese的逻辑差不多,只不过这个是应对错误情况使用的

on关键字

这个其实在之前我们学mixin的时候就遇到了,不过on关键字在不同场景下的作用不太一样

在try on中

我们刚才说的try catch的catch的参数是error,也就是接受一切错误并反馈

但是这里try on 就不是了

在这里 on = 只捕获某种指定类型的异常

DART已复制
try {
   ...
}
on 异常类型 {
   ...
}

例如刚才的这个例子返回值是 IntegerDivisionByZeroException

​ image-20260418210253654

而我们只提取这一个问题并输出就行了

DART已复制
void main() {
  try {
    int a = 10 ~/ 0; // 整数除零,会报错

    print(a);
  } on IntegerDivisionByZeroException {
    print("不能除0");
  }
}

​ image-20260418210401742

甚至还能这样玩

DART已复制
void main() {
  try {
    //List越界
    List list = [1, 2];
    print(list[5]);
  }on RangeError {
    print("越界");
  }

  try {
    // 整数除0
    int a = 10 ~/ 0;
  } on IntegerDivisionByZeroException {
    print("除零");
  }

  try {
    // 格式错误
    int.parse("abc");
  } on FormatException {
    print("格式错误");
  } 
}

在mixin中

在mixin中我们知道with关键字可以让类使用mixin里的参数和方法

而我们在mixin中使用on就是限制只有哪些类可以使用这个mixin

DART已复制
class Animal {
  //所有的动物都会吃东西
  void eat() {
    print("动物吃东西");
  }
}

//鸟继承动物类
class Bird extends Animal {
  void layEgg() {
    print("鸟下蛋");
  }
}

//猫继承动物类
class Cat extends Animal {}

//狗继承动物类
class Dog extends Animal {}

//但是飞行和下蛋能力我只允许鸟可以
mixin Fly on Bird {
  void fly() {
    eat();

    layEgg();

    print("鸟在飞");
  }
}

//这样麻雀类继承鸟类就可以飞了
class Sparrow extends Bird with Fly {}

void main() {
  Sparrow s = Sparrow();

  s.fly();
}