您的位置:首页 > 娱乐 > 八卦 > 动态ppt模板下载免费完整版_设计logo图片_国产系统2345_免费发帖论坛大全

动态ppt模板下载免费完整版_设计logo图片_国产系统2345_免费发帖论坛大全

2024/12/22 17:24:21 来源:https://blog.csdn.net/weixin_40323532/article/details/144142730  浏览:    关键词:动态ppt模板下载免费完整版_设计logo图片_国产系统2345_免费发帖论坛大全
动态ppt模板下载免费完整版_设计logo图片_国产系统2345_免费发帖论坛大全

在 Flutter 中,FutureStream 都是用于处理异步操作的类,它们都基于 Dart 的异步编程模型,但是它们的使用场景和工作方式有所不同。以下是它们的区别以及各自适用的场景。

目录

    • 一、Future
      • 1、基本使用
      • 2、异常处理
        • 1. catchError
        • 2. onError
        • 3、`catchError` 和 `onError` 的区别
        • 4. 捕获多个错误
        • 5. 错误的传播
      • 总结
    • 二、Stream
      • 1、基本使用
      • 2、异常处理
        • 1. `onError` 处理器
        • 2. `try-catch` 语句
        • 3. 异常后流的状态
        • 4. 流的中断
        • 5. 恢复流
        • 6. 流异常的示例
      • 总结
    • 三、 结合使用 `Future` 和 `Stream`
    • 四、总结
      • 1、区别
      • 2、选择 `Future` 还是 `Stream`
    • 四、疑问
      • 1、Stream 流是按照顺序执行的吗?
        • 1. 顺序性
        • 2. 顺序的保证
      • 2、Stream async* 和 yield 的解释这三个必须要配套使用吗?,不适用 yield 行吗?
        • 1. `Stream` 与 `async*`
        • 2. `async*` 和 `yield` 必须配合使用吗?
        • 3. 不使用 `yield` 行不行?
        • 4. 如何使用 `async*` 生成异步数据流?
        • 总结

一、Future

1、基本使用

Future 是一个表示一个可能还未完成的异步操作的对象。它表示一个将来某个时间点会返回一个结果或错误的计算。

  • 特点
    • Future 代表的是一个 单次 异步操作。
    • 只能返回一次结果或错误,不会再有后续的值。
    • 在调用时,它会返回一个 Future 对象,可以通过 thenawait 等方法获取结果。
    • 如果操作失败,可以通过 catchErroronError 进行错误处理。
  • 使用场景
    • 当你需要等待一个单一的异步结果时,使用 Future
    • 比如从网络获取数据,执行一个数据库查询,或读取一个文件等一次性的操作。
  • 示例代码
// 使用 Future 的示例
Future<String> fetchData() async {// 模拟异步操作await Future.delayed(Duration(seconds: 2));return "Data fetched successfully!";
}void main() async {try {String data = await fetchData();print(data); // 输出 "Data fetched successfully!"} catch (e) {print("Error: $e");}
}

在上面的示例中,fetchData 返回一个 Future<String>,它表示一个将来完成的异步操作。使用 await 来等待这个操作完成并获得结果。

2、异常处理

1. catchError

catchError 是用于捕获和处理 Future 发生错误的一种方式。当 Future 执行失败时,它会触发传给 catchError 的回调函数。这个回调函数可以接受错误和栈跟踪信息。

示例:

Future<int> divide(int a, int b) {return Future.delayed(Duration(seconds: 1), () {if (b == 0) {throw Exception('Cannot divide by zero!');}return a ~/ b;});
}void main() {divide(10, 0).catchError((e) {print('Error: $e');});// Output: Error: Exception: Cannot divide by zero!
}

在这个例子中,当 b 为 0 时,Future 会抛出一个 Exception,并且 catchError 捕获并打印这个错误。

catchError 的用法细节:

  • 返回值的传递catchError 会继续执行 Future 链中的后续操作,因此如果你想在错误发生时返回一个默认值,可以在 catchError 中指定。
Future<int> divide(int a, int b) {return Future.delayed(Duration(seconds: 1), () {if (b == 0) {throw Exception('Cannot divide by zero!');}return a ~/ b;}).catchError((e) {print('Handled error: $e');return -1;  // 返回默认值});
}void main() async {var result = await divide(10, 0);print('Result: $result');  // 输出: Handled error: Exception: Cannot divide by zero!//         Result: -1
}
2. onError

onErrorFuture 的另一种错误处理方式。它与 catchError 类似,但它是 Future 构造函数的一部分,通常用于直接在 Future 构造时附加错误处理。

示例:

Future<int> divide(int a, int b) {return Future.delayed(Duration(seconds: 1), () {if (b == 0) {throw Exception('Cannot divide by zero!');}return a ~/ b;}).onError((error, stackTrace) {print('Caught an error: $error');return -1;  // 返回默认值});
}void main() async {var result = await divide(10, 0);print('Result: $result');  // 输出: Caught an error: Exception: Cannot divide by zero!//         Result: -1
}
3、catchErroronError 的区别
  • catchError 是用于捕获在 Future 执行时抛出的异常,它通常用于链式调用中捕获错误。
  • onErrorFuture 的一种附加错误处理机制,它将错误处理直接嵌入到 Future 构造中。

尽管 catchErroronError 都可以捕获错误并返回一个默认值或执行某些操作,但 catchError 更灵活,通常在复杂的异步链式操作中使用。

4. 捕获多个错误

如果你需要捕获多个错误,可以将 catchErroronError 绑定到多个 Future 链条上。这样可以对不同类型的错误进行不同的处理。

示例:

Future<void> asyncFunction() {return Future.delayed(Duration(seconds: 1), () {throw Exception('Something went wrong!');});
}void main() {asyncFunction().catchError((e) {print('Caught error: $e');}).catchError((e) {print('Another handler for errors: $e');});// Output: Caught error: Exception: Something went wrong!
}
5. 错误的传播

如果在 Future 中没有处理错误,错误将会被传播,直到被外部捕获或程序崩溃。因此,适当的错误处理不仅可以帮助捕获问题,还可以避免未捕获的异常导致程序崩溃。

总结

在 Dart 中,catchErroronError 都可以用于处理异步操作中的错误。它们的主要区别在于用法和灵活性,选择哪一个取决于你的代码结构和需求。

二、Stream

1、基本使用

Stream 是一个表示一系列异步事件的对象,它允许你在未来的时间点接收多个值。

  • 特点
    • Stream 代表的是 多个异步事件
    • 它会按顺序提供一系列的结果(可以是零个或多个),通常用于处理实时数据流。
    • 可以是单向的,也可以是广播流(多个监听者可以订阅)。
    • 你可以通过 listen 方法来监听事件流。
    • Stream 还支持 await for 语法,可以等待并处理每个事件。
  • 使用场景
    • 当你需要处理一个 数据流多个值 时,使用 Stream
    • 比如处理实时数据(如 WebSocket 数据流、用户输入事件流、文件变化等)。
  • 示例代码
// 使用 Stream 的示例
Stream<int> generateNumbers() async* {for (int i = 0; i < 5; i++) {await Future.delayed(Duration(seconds: 1));yield i; // 每秒产生一个数字}
}void main() async {await for (var number in generateNumbers()) {print(number); // 输出:0, 1, 2, 3, 4}
}

在这个示例中,generateNumbers 返回一个 Stream<int>,它每秒返回一个整数。通过 await for 循环,我们可以逐个接收流中的数据。

2、异常处理

当流中发生异常时,有几种方式来处理这些异常,使得流能够继续工作或适当地终止。

1. onError 处理器

如果你使用 Stream.listen 方法来监听流,可以通过传入 onError 回调来处理流中的异常。当流抛出异常时,onError 处理器会被触发。

Stream<int> generateNumbersWithError() async* {yield 1;yield 2;throw Exception('Something went wrong');yield 3;  // 这一行永远不会执行
}void main() {generateNumbersWithError().listen((data) {print('Received: $data');},onError: (error) {print('Caught error: $error');},onDone: () {print('Stream is done');},);
}

输出:

Received: 1
Received: 2
Caught error: Exception: Something went wrong
Stream is done

在这个例子中,当 Stream 中的 Exception 被抛出时,onError 回调会捕获并打印出错误信息。yield 3 后的代码不会执行,因为流在抛出异常后被中断。

2. try-catch 语句

在异步生成器(如 async*)中,你可以使用 try-catch 来捕获异常,这可以防止异常导致流中断。

Stream<int> generateNumbersWithErrorHandled() async* {try {yield 1;yield 2;throw Exception('Something went wrong');yield 3;  // 这一行不会执行} catch (e) {print('Caught error: $e');}
}void main() async {await for (var data in generateNumbersWithErrorHandled()) {print('Received: $data');}
}

输出:

Received: 1
Received: 2
Caught error: Exception: Something went wrong

在这个例子中,即使抛出异常,Stream 仍然能够继续执行,只是异常会被捕获并处理。

3. 异常后流的状态

Stream 抛出异常后,流会进入错误状态,并且不再发出任何数据,除非你有合适的机制来恢复流。

  • 如果流中的 onError 回调没有捕获异常,流会直接终止。
  • 如果你在 Stream 中使用 try-catch 捕获了异常,流可以继续正常工作,继续发送后续的数据。
4. 流的中断

流的中断意味着流不再继续发出事件。中断的原因通常有以下几种:

  • 异常抛出:如果流中的某个操作抛出了异常,流会被中断,后续的事件不会再触发。
  • 用户主动取消订阅:如果你使用 StreamSubscription 来订阅流,并主动调用 cancel(),流也会中断。
  • 流结束:如果流完成(即没有更多的事件要发出),流会进入完成状态。
5. 恢复流

如果你希望在流发生异常后恢复流的工作,可以通过重新订阅流或使用一些复合的错误处理机制。

例如,在监听流时使用 onError 捕获错误并在错误发生时重新启动流:

Stream<int> generateNumbersWithError() async* {yield 1;yield 2;throw Exception('Something went wrong');yield 3;
}void main() {Stream<int> stream = generateNumbersWithError();stream.listen((data) {print('Received: $data');},onError: (error) {print('Caught error: $error');// 重新启动流stream.listen((data) => print('Retry received: $data'),onError: (e) => print('Retry error: $e'),onDone: () => print('Retry stream is done'),);},onDone: () => print('Stream is done'),);
}

在这种情况下,流会在错误发生时重新启动。这允许你捕获错误并尝试恢复流的执行。

6. 流异常的示例

假设有一个 Stream 生成器,它在生成某个事件时发生异常:

Stream<int> generateNumbersWithError() async* {yield 1;yield 2;throw Exception('Unexpected error');yield 3;  // 这行永远不会执行
}void main() async {try {await for (var number in generateNumbersWithError()) {print('Received: $number');}} catch (e) {print('Caught error: $e');}
}

输出:

Received: 1
Received: 2
Caught error: Exception: Unexpected error

在这个例子中,异常会导致流中断,后续的事件不会被处理,且异常被捕获。

总结

  • 流中断:当流遇到异常时,流会进入错误状态并停止发出事件。
  • 异常处理:你可以通过 onError 回调或 try-catch 语句捕获和处理异常。
  • 恢复流:在流发生异常时,可以选择恢复流的工作,例如通过重新订阅流。

三、 结合使用 FutureStream

在某些情况下,FutureStream 可以结合使用。例如,如果你有一个 Future 返回一个数据集,而这个数据集可以被逐步处理,那么你可以将 Future 的结果转换成一个 Stream 来进行逐项处理。

Future<List<int>> fetchData() async {return [1, 2, 3, 4, 5];
}Stream<int> fetchDataAsStream() async* {List<int> data = await fetchData();for (var item in data) {yield item;}
}void main() async {await for (var number in fetchDataAsStream()) {print(number); // 输出 1, 2, 3, 4, 5}
}

在这个例子中,fetchData 是一个 Future,而 fetchDataAsStream 将其转换成了一个 Stream,使得我们能够以流的形式逐项处理数据。

总结

  • Future 适合用于处理 单次 的异步操作,返回一个值或错误。
  • Stream 适合用于处理 多次 的异步事件或数据流,允许你持续接收多个值。

了解它们的区别和使用场景可以帮助你更好地选择异步操作的方式,从而提高代码的可读性和性能。

四、总结

1、区别

特性FutureStream
返回值只返回一个值或一个错误持续返回多个值或错误
生命周期一次性操作,完成后不再有新的值持续发出多个值(或者是事件)
异步操作适用于单次异步操作适用于多次异步事件或数据流
操作方式thencatchErrorawaitlistenawait foraddaddError

2、选择 Future 还是 Stream

  • 使用 Future
    • 你在处理一个单次的异步操作时。
    • 比如从网络获取数据、计算结果、执行数据库操作等。
    • 示例:登录请求、获取单个 API 响应、读取文件内容。
  • 使用 Stream
    • 当你需要处理 多个异步事件,例如实时数据流或变化时。
    • 比如 WebSocket 消息、实时位置更新、文件读取(大文件分片)等。
    • 示例:实时聊天消息、连续的数据更新、传感器数据流等。

四、疑问

1、Stream 流是按照顺序执行的吗?

是的,Stream 在 Dart 中是 按顺序 执行的。具体来说,Stream 中的事件(数据或错误)会按照它们被 产生发出 的顺序进行传递和处理。

1. 顺序性

在 Dart 中,Stream 会按照 事件发出的顺序 将这些事件传递给订阅者。也就是说,先发出的事件会先被监听器处理。

例如,如果你有一个 Stream 生成数据流,并且在每个数据项之间有延时,那么监听器将会按照数据产生的顺序处理每个事件。

示例代码:顺序执行的 Stream

Stream<int> generateNumbers() async* {for (int i = 0; i < 3; i++) {await Future.delayed(Duration(seconds: 1));  // 模拟延时yield i;  // 按顺序发出数据}
}void main() async {await for (var number in generateNumbers()) {print('Received: $number');  // 按顺序输出}
}

输出:

Received: 0
Received: 1
Received: 2

在这个例子中,数据流是按顺序传递给监听器的,即 012 按照生成的顺序被逐个输出。

2. 顺序的保证

Stream 本身的设计保证了事件的顺序。无论你是通过 await for 或者 listen 来处理事件,事件会按照发出顺序依次传递给你。

通过 listen 监听的顺序

Stream<int> generateNumbers() async* {for (int i = 0; i < 3; i++) {await Future.delayed(Duration(seconds: 1));yield i;}
}void main() {generateNumbers().listen((data) {print('Received: $data');  // 按顺序输出});
}

这段代码会输出:

Received: 0
Received: 1
Received: 2

如上所示,数据按照顺序传递。

2、Stream async* 和 yield 的解释这三个必须要配套使用吗?,不适用 yield 行吗?

在 Dart 中,Streamasync*yield 是紧密关联的,但它们不一定是必须同时使用的。它们之间的关系可以分开解释,看看如何组合使用,或者是否可以在没有 yield 的情况下使用 async*

1. Streamasync*

Stream 是 Dart 中用于处理异步数据流的核心概念。Stream 对象用于处理一系列异步事件,而 async* 是定义异步生成器(异步迭代器)的一种语法。async* 允许你生成一个 Stream,并通过 yield 来发出数据。

  • async* 标识一个异步生成器函数,它返回一个 Stream
  • yield 用于在异步生成器中逐个发出数据。
2. async*yield 必须配合使用吗?
  • async*yield 一般是配套使用的,但你也可以只使用 async*,并没有强制要求一定要用 yield
  • 如果你不需要发出数据(即你不想使用 yield),你也可以用 async* 作为一个简单的异步函数来返回一个空的 Stream,或者使用 await 来发出异步的结果。
3. 不使用 yield 行不行?

是的,可以在没有 yield 的情况下使用 async*,但通常这样做的结果是流不会发出任何数据。在这种情况下,Stream 会是一个空的流,或者说它在没有任何数据的情况下完成。

示例 1:不使用 yield,生成一个空的流

Stream<int> generateEmptyStream() async* {// 什么都不发出
}void main() async {await for (var value in generateEmptyStream()) {print(value);  // 这里不会有任何输出}
}

在这个例子中,async* 只是声明了一个异步生成器,但是没有 yield,因此返回的 Stream 是空的,不会有任何数据输出。

4. 如何使用 async* 生成异步数据流?

async* 用于返回 Stream,可以通过 yield 来逐个发出数据。你也可以结合 await 来进行异步操作后再发出数据。这是一个典型的用法:

Stream<int> generateNumbers() async* {for (int i = 1; i <= 5; i++) {await Future.delayed(Duration(seconds: 1));  // 模拟异步操作yield i;  // 发出数据}
}void main() async {await for (var number in generateNumbers()) {print(number);}
}

输出:

1
2
3
4
5

在这个例子中,async* 通过 yield 发出了多个数字,每次发出时都延迟 1 秒。

总结
  • async*yield 通常一起使用来生成和发出异步数据流。
  • 不一定非要有 yield (但不使用 yield 意义不大),但如果你希望生成一个有数据的流,就需要使用 yield 或其他发出数据的方式(例如 yield*)。
  • 如果你在 async* 中没有 yield,返回的 Stream 将不会发出任何数据,通常这种情况用于创建空流或只执行异步操作的函数。

因此,虽然 async*yield 是紧密相关的,但它们不必总是同时使用。如果不使用 yield,可以生成一个空流或执行异步操作,但不会有数据发出。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com