Skip to content

异步编程

Future 的基本概念与使用

Future 的概念

Future 表示一个异步计算的结果,与 JavaScript 中的 Promise 类似。用于处理异步操作,异步处理成功就执行成功的操作,异步处理失败就执行失败的操作。

一个 Future 对象只会对应一个结果,要么成功,要么失败。Future 的所有 API 返回值类型都是 Future

Future.then

then 方法用于注册成功回调。

示例:

dart
void main() {
  Future(() => 42).then((value) {
    print('Result: $value');
  });
}

其中,then 方法还可以接收一个可选的 onError 参数,用于注册失败回调。

示例:

dart
void main() {
  Future.error('Error occurred').then((value) {
    print('Result: $value');
  }, onError: (error) {
    print('Error: $error');
  });
}

Future.catchError

catchError 方法用于注册失败回调。

示例:

dart
void main() {
  Future(() => 42).then((value) {
    print('Result: $value');
  }).catchError((error) {
    print('Error: $error');
  });
}

在上方代码中,当 Future 执行失败时,会调用 catchError 方法注册的回调函数,不会调用 then 方法注册的回调函数。

Future.whenComplete

whenComplete 方法用于注册无论成功或失败都会执行的回调。例如在关闭文件、释放资源、关闭加载动画等场景。

示例:

dart
void main() {
  Future(() => 42).then((value) {
    print('Result: $value');
  }).catchError((error) {
    print('Error: $error');
  }).whenComplete(() {
    print('Done');
  });
}

Future.wait

wait 方法用于等待多个 Future 完成,接收一个 Future 数组,当所有 Future 都完成时返回一个 Future,如果其中一个 Future 失败,则触发失败的回调。

示例:

dart
void main() {
  var future1 = Future.delayed(Duration(seconds: 2), () => 1);
  var future2 = Future.delayed(Duration(seconds: 1), () => 2);

  Future.wait([future1, future2]).then((value) {
    print('Result: $value');
  }).catchError((error) {
    print('Error: $error');
  });
}

async 和 await

Dart 使用 asyncawait 简化异步编程,使异步任务串行化、代码更加清晰易读。

使用 async 声明异步函数,使用 await 等待异步结果。

无论是在 Dart 或是 JavaScript 中,asyncawait 都只是语法糖,本质上编译器/解释器会将其转换为 FuturePromise

例如在下面的场景中,用户先登录,登录成功后根据用户 ID 获取用户信息,最后将用户信息存储到本地。

dart
// 登录
Future<void> login() async {
  await Future.delayed(Duration(seconds: 1));
  print('Login success');
}

// 获取用户信息
Future<String> getUserInfo(int userId) async {
  await Future.delayed(Duration(seconds: 1));
  return 'User: $userId';
}

// 保存用户信息
Future<void> saveUserInfo(String userInfo) async {
  await Future.delayed(Duration(seconds: 1));
  print('Save user info: $userInfo');
}

在没有引入 asyncawait 的情况下,会出现回调地狱(层层嵌套)的情况。代码如下:

dart
void main() {
  login().then((_) {
    getUserInfo(1).then((userInfo) {
      saveUserInfo(userInfo).then((_) {
        print('All done');
      });
    });
  });
}

为了解决回调地狱的问题,可以使用下面两种方式:

  1. 使用 then 方法
dart
void main() {
  login().then((_) {
    return getUserInfo(1);
  }).then((userInfo) {
    return saveUserInfo(userInfo);
  }).then((_) {
    print('All done');
  });
}
  1. 使用 async 和 await
dart
void main() async {
  try {
    await login();
    var userInfo = await getUserInfo(1);
    await saveUserInfo(userInfo);
    print('All done');
  } catch (e) {
    print('Error: $e');
  }
}

Stream 的概念与使用

Stream 的概念

Stream 是一种表示异步数据序列的抽象,允许处理一系列异步事件,例如从文件读取数据、处理网络响应或者监听用户输入等。Stream 提供了一种简洁而强大的方式来处理这些异步数据流。

Stream 有三个基本概念:

  • 数据源:Stream 从数据源获取数据。数据源可以是文件、网络、用户输入等。
  • 监听器(Listener):你可以添加监听器到 Stream 上,以便在数据到达时处理数据。
  • 事件:Stream 可以发出三种类型的事件,数据(data)、错误(error)和结束(done)。

监听 Stream

Dart 提供了一些基本的 Stream 类,比如 StreamController,可以用来创建自定义的 Stream。

dart
import 'dart:async';

void main() async {
  // 创建一个 StreamController
  StreamController<int> controller = StreamController<int>();

  // 监听 Stream
  controller.stream.listen(
    (data) {
      print('Received data: $data');
    },
    onError: (error) {
      print('Error: $error');
    },
    onDone: () {
      print('Stream is done.');
    },
    cancelOnError: true,
  );

  // 添加数据到 Stream
  controller.add(1);
  controller.add(2);
  controller.add(3);

  // 关闭 Stream
  controller.close();
}

转换 Stream

Dart 提供了许多 StreamTransformer 类,允许你对 Stream 进行各种变换操作,比如映射(map)、过滤(filter)和聚合(reduce)等。

dart
import 'dart:async';

void main() async {
  // 创建一个简单的 Stream
  Stream<int> stream = Stream.fromIterable([1, 2, 3, 4, 5]);

  // 使用 map 变换 Stream
  stream
      .map((data) => data * 2)
      .listen(
        (data) {
          print('Mapped data: $data');
        },
      );
}

处理 Stream 错误

通过 onError 回调来处理 Stream 中的错误。

dart
import 'dart:async';

void main() async {
  // 创建一个带有错误的 Stream
  Stream<int> stream = Stream.fromIterable([1, 2, 3])
      .concat(Stream.error(Exception('An error occurred')));

  stream.listen(
    (data) {
      print('Received data: $data');
    },
    onError: (error) {
      print('Error: $error');
    },
  );
}

常见的 Stream 类型

  • BroadcastStream:可以有多个监听器的 Stream。
  • SingleSubscriptionStream:只能有一个监听器的 Stream。
  • EventSinkEventStream:用于实现自定义的 Stream 控制器和 Stream。

高级用法

  1. 使用 async* 创建自定义 Stream

使用 async* 语法来创建自定义的 Stream。

dart
import 'dart:async';

Stream<int> customStream() async* {
  for (int i = 0; i < 5; i++) {
    await Future.delayed(Duration(seconds: 1)); // 模拟异步操作
    yield i;
  }
}

void main() async {
  customStream().listen(
    (data) {
      print('Received data: $data');
    },
  );
}
  1. 结合 Future 使用 Stream

Stream 可以和 Future 结合使用,以便在异步操作完成后继续处理数据。

dart
import 'dart:async';

void main() async {
  Future<int> fetchData() async {
    await Future.delayed(Duration(seconds: 1)); // 模拟异步操作
    return 42;
  }

  Stream<int> stream = Stream.fromFuture(fetchData());

  stream.listen(
    (data) {
      print('Received data: $data');
    },
  );
}

异步生成器(yield 和 yield*)

yield

使用 yield 逐步生成数据。

示例:

dart
Stream<int> countStream() async* {
  for (int i = 1; i <= 3; i++) {
    yield i;
  }
}

void main() async {
  await for (var value in countStream()) {
    print('Value: $value');
  }
}

yield*

使用 yield* 转发另一个生成器。

示例:

dart
Stream<int> countStream() async* {
  yield* Stream.fromIterable([1, 2, 3]);
}

void main() async {
  await for (var value in countStream()) {
    print('Value: $value');
  }
}
编程洪同学服务平台是一个广泛收集编程相关内容和资源,旨在满足编程爱好者和专业开发人员的需求的网站。无论您是初学者还是经验丰富的开发者,都可以在这里找到有用的信息和资料,我们将助您提升编程技能和知识。
专业开发
高端定制
售后无忧
站内资源均为本站制作或收集于互联网等平台,如有侵权,请第一时间联系本站,敬请谅解!本站资源仅限于学习与参考,严禁用于各种非法活动,否则后果自行负责,本站概不承担!