Flutter中同步与异步

一,同步/异步的理解

1,await:同步机制

同步操作会阻止其他操作执行,直到完成为止。同步就好比打电话一样,打电话时都是一个人在说另一个人听,一个人在说的时候另一个人等待,等另一个人说完后再接着说。

2,async:异步机制

异步操作一旦启动,就允许其他操作在其完成之前执行。异步就好比发邮件一样,收件人和发件人都不需要相互等待,发件人写完邮件的时候简单的点个发送就可以了,收件人收到后就可以阅读啦,收件人和发件人不需要相互依赖、不需要相互等待。

二,Dart中同步/异步。

async 和 await 关键字构成了异步编程的基础,它们极大地简化了异步操作的处理流程。async 关键字用于声明一个函数为异步函数,这意味着该函数的执行可能不会立即完成,并且会返回一个 Future 对象。

1,Future 是 Dart 中的一个核心类,代表一个可能在未来某个时间点返回结果的计算。

当在 async 函数内部遇到 await 关键字时,执行流程会暂停,直到 await 后面的异步操作完成。

这种暂停并不会阻塞整个线程,而是允许 Dart 的事件循环继续处理其他事件,如用户交互或动画,从而保持应用的响应性。

2,使用 await 的优势在于它能够让异步代码的逻辑流程更加直观和清晰。

开发者不再需要通过嵌套回调(俗称"回调地狱")来处理异步操作的结果,而是可以以近似同步的方式编写代码,使得逻辑更容易理解和维护。

3,async 和 await 在错误处理方面也提供了便利。

在 async 函数中,可以使用传统的 try-catch 结构来捕获异步操作中抛出的异常,这比处理 Future 的 catchError 方法更加直观。

三,Flutter中同步/异步的使用

1,StreamBuilder/FutureBuilder

在 Flutter 中,StreamBuilderFutureBuilder 都是用于处理异步数据源的常用组件。它们允许你在等待异步操作完成时更新 UI。尽管它们的功能类似,但它们适用于不同的异步数据源类型。

1.1,FutureBuilder

FutureBuilder 用于处理 Future 类型的异步数据源。Future 表示一个将来可能会完成的单一异步操作,例如一次性网络请求。

基本用法
  • 适用场景: 当你有一个一次性的异步操作,例如从网络加载数据,执行数据库查询等。

  • 构造函数参数:

    • future: 一个 Future 对象,表示要等待的异步操作。

    • builder: 一个函数,构建UI,并根据 Future 的状态来更新UI。

      import 'package:flutter/material.dart';
      
      class MyFutureBuilder extends StatelessWidget {
        Future<String> fetchData() async {
          await Future.delayed(Duration(seconds: 2)); // 模拟网络延迟
          return 'Hello, FutureBuilder!';
        }
      
        @override
        Widget build(BuildContext context) {
          return Scaffold(
            appBar: AppBar(title: Text('FutureBuilder Example')),
            body: Center(
              child: FutureBuilder<String>(
                future: fetchData(),
                builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
                  if (snapshot.connectionState == ConnectionState.waiting) {
                    return CircularProgressIndicator();
                  } else if (snapshot.hasError) {
                    return Text('Error: ${snapshot.error}');
                  } else {
                    return Text('Result: ${snapshot.data}');
                  }
                },
              ),
            ),
          );
        }
      }
      
      void main() => runApp(MaterialApp(home: MyFutureBuilder()));
      

      1.2,StreamBuilder

      StreamBuilder 用于处理 Stream 类型的异步数据源。Stream 表示一系列的异步事件或数据,例如连续的传感器数据、WebSocket 数据等。

      基本用法
    • 适用场景: 当你有多个异步数据或事件的流,例如实时更新的数据、传感器数据等。

    • 构造函数参数:

      • stream: 一个 Stream 对象,表示要监听的异步数据流。

      • builder: 一个函数,构建UI,并根据 Stream 的状态和数据来更新UI。

        import 'dart:async';
        import 'package:flutter/material.dart';
        
        class MyStreamBuilder extends StatelessWidget {
          Stream<int> counterStream() async* {
            for (int i = 0; i < 10; i++) {
              await Future.delayed(Duration(seconds: 1));
              yield i;
            }
          }
        
          @override
          Widget build(BuildContext context) {
            return Scaffold(
              appBar: AppBar(title: Text('StreamBuilder Example')),
              body: Center(
                child: StreamBuilder<int>(
                  stream: counterStream(),
                  builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
                    if (snapshot.connectionState == ConnectionState.waiting) {
                      return CircularProgressIndicator();
                    } else if (snapshot.hasError) {
                      return Text('Error: ${snapshot.error}');
                    } else if (!snapshot.hasData) {
                      return Text('No data');
                    } else {
                      return Text('Counter: ${snapshot.data}');
                    }
                  },
                ),
              ),
            );
          }
        }
        void main() => runApp(MaterialApp(home: MyStreamBuilder()));
        

        1.3,区别总结

      • 数据源类型:

        • FutureBuilder:处理一次性异步操作的 Future

        • StreamBuilder:处理连续异步数据流的 Stream

      • 更新机制:

        • FutureBuilder:在 Future 完成或失败后构建一次 UI。

        • StreamBuilder:每次 Stream 发送新数据或状态变化时更新 UI。

      • 适用场景:

        • FutureBuilder:适用于单次的异步操作,例如网络请求、数据库查询等。

        • StreamBuilder:适用于多次的异步数据更新,例如实时数据、传感器数据、WebSocket 数据等。

          2,Future.wait/Future.any

          2.1,Future.wait

          Future.wait 等待所有提供的 Future 对象完成,并在所有 Future 都完成后返回一个包含每个 Future 结果的列表。如果任何一个 Future 抛出异常,则 Future.wait 会返回第一个抛出的异常。

          用法
        • 适用场景: 当你有多个并发的异步任务,并且需要等待所有任务都完成后再继续执行后续操作。

          import 'dart:async';
          
          void main() async {
            print('Start');
          
            Future<int> task1 = Future.delayed(Duration(seconds: 2), () => 1);
            Future<int> task2 = Future.delayed(Duration(seconds: 3), () => 2);
            Future<int> task3 = Future.delayed(Duration(seconds: 1), () => 3);
          
            List<int> results = await Future.wait([task1, task2, task3]);
            print('Results: $results'); // [1, 2, 3]
          
            print('End');
          }
          

          2.2,Future.any

          Future.any 等待提供的 Future 对象中第一个完成的任务,并返回该任务的结果。如果所有 Future 都抛出异常,则 Future.any 会返回最后一个抛出的异常。

          用法
        • 适用场景: 当你有多个并发的异步任务,并且只需要其中任何一个任务完成后就继续执行后续操作。

          import 'dart:async';
          
          void main() async {
            print('Start');
          
            Future<int> task1 = Future.delayed(Duration(seconds: 2), () => 1);
            Future<int> task2 = Future.delayed(Duration(seconds: 3), () => 2);
            Future<int> task3 = Future.delayed(Duration(seconds: 1), () => 3);
          
            int result = await Future.any([task1, task2, task3]);
            print('First completed result: $result'); // 3
          
            print('End');
          }
          

          在这个示例中,Future.any 会在 task3 完成后立即返回结果,因为 task3 是最先完成的任务。

          在这个示例中,Future.any 会在 task3 完成后立即返回结果,因为 task3 是最先完成的任务。

          2.3,区别总结

        • 行为方式:

          • Future.wait 等待所有 Future 对象完成,并返回所有结果。

          • Future.any 等待第一个完成的 Future 对象,并返回其结果。

        • 错误处理:

          • Future.wait 如果任何一个 Future 抛出异常,则返回第一个抛出的异常。

          • Future.any 如果所有 Future 都抛出异常,则返回最后一个抛出的异常。

        • 适用场景:

          • Future.wait 适用于需要所有并发任务都完成后再处理结果的场景。

          • Future.any 适用于只需要其中任何一个任务完成即可继续执行的场景。

            2.4,实践中的应用场景

            使用 Future.wait

            假设你在开发一个应用,需要同时发起多个网络请求,只有在所有请求完成后才能继续处理响应数据。这时你可以使用 Future.wait

            import 'dart:async';
            
            void main() async {
              Future<String> fetchUserData() async {
                await Future.delayed(Duration(seconds: 2));
                return 'User data';
              }
            
              Future<String> fetchOrders() async {
                await Future.delayed(Duration(seconds: 3));
                return 'Orders';
              }
            
              Future<String> fetchSettings() async {
                await Future.delayed(Duration(seconds: 1));
                return 'Settings';
              }
            
              print('Fetching data...');
            
              List<String> results = await Future.wait([
                fetchUserData(),
                fetchOrders(),
                fetchSettings(),
              ]);
            
              print('All data fetched: $results');
            }
            
            使用 Future.any

            假设你在开发一个应用,需要从多个服务器中获取数据,只要任何一个服务器返回数据即可。这时你可以使用 Future.any

            import 'dart:async';
            
            void main() async {
              Future<String> fetchFromServer1() async {
                await Future.delayed(Duration(seconds: 2));
                return 'Data from server 1';
              }
            
              Future<String> fetchFromServer2() async {
                await Future.delayed(Duration(seconds: 3));
                return 'Data from server 2';
              }
            
              Future<String> fetchFromServer3() async {
                await Future.delayed(Duration(seconds: 1));
                return 'Data from server 3';
              }
            
              print('Fetching data...');
            
              String result = await Future.any([
                fetchFromServer1(),
                fetchFromServer2(),
                fetchFromServer3(),
              ]);
            
              print('First data fetched: $result');
            }
            

            3,Future.doWhile/Future.forEach

            3.1,Future.doWhile

            Future.doWhile 用于执行一个异步循环,直到条件不满足为止。循环体中的每次迭代是异步的,并且需要返回一个 Future<bool>,表示是否继续循环。

            用法
          • 适用于需要重复执行异步操作,直到某个条件不再满足的场景。

            import 'dart:async';
            
            void main() async {
              int counter = 0;
            
              print('Start');
            
              await Future.doWhile(() async {
                counter++;
                print('Counter: $counter');
                await Future.delayed(Duration(seconds: 1)); // 模拟异步操作
                return counter < 5; // 继续循环直到 counter >= 5
              });
            
              print('End');
            }
            

            3.2,Future.forEach

            Future.forEach 用于对集合中的每个元素执行异步操作。它依次执行每个元素的异步操作,等待当前操作完成后再执行下一个操作。

            用法
          • 适用于需要对集合中的每个元素执行异步操作的场景。

            import 'dart:async';
            
            void main() async {
              List<int> numbers = [1, 2, 3, 4, 5];
            
              print('Start');
            
              await Future.forEach(numbers, (number) async {
                print('Processing number: $number');
                await Future.delayed(Duration(seconds: 1)); // 模拟异步操作
              });
            
              print('End');
            }
            

            3.3,区别总结

          • 控制流方式:

            • Future.doWhile:用于执行一个异步循环,直到条件返回 false 为止。适合在不知道具体迭代次数的情况下执行重复的异步操作。

            • Future.forEach:用于对集合中的每个元素执行异步操作,适合在知道具体迭代次数的情况下对集合进行异步处理。

          • 返回类型:

            • Future.doWhile:接受一个返回 Future<bool> 的函数作为参数。

            • Future.forEach:接受一个返回 Future<void> 的函数作为参数。

          • 终止条件:

            • Future.doWhile:循环的终止条件由函数返回的布尔值决定。

            • Future.forEach:循环的终止条件是集合中所有元素都处理完毕。

          4,Future异常处理。

          Flutter 和 Dart 提供了几种方法来捕获和处理 Future 异常,包括使用 try-catch 语句、catchError 方法以及在异步函数中处理异常。

          4.1,try-catch

            import 'dart:async';
          
            Future<void> fetchData() async {
              try {
                await Future.delayed(Duration(seconds: 2));
                throw Exception('Failed to fetch data'); // 模拟异常
              } catch (e) {
                print('Caught an exception: $e');
              }
            }
          
            void main() async {
              await fetchData();
              print('Done');
            }
          

          4.2,catchError

          catchError 方法需要一个回调函数,该函数接收异常作为参数。

            import 'dart:async';
          
            Future<void> fetchData() {
              return Future.delayed(Duration(seconds: 2))
                  .then((_) {
                    throw Exception('Failed to fetch data'); // 模拟异常
                  })
                  .catchError((e) {
                    print('Caught an exception: $e');
                  });
            }
          
            void main() async {
              await fetchData();
              print('Done');
            }
          
          4.2.1,使用 then 和 catchError 组合

          thencatchError 方法可以组合使用,以便在 Future 完成时处理结果,并在出现异常时进行错误处理。

            import 'dart:async';
          
            Future<void> fetchData() {
              return Future.delayed(Duration(seconds: 2))
                  .then((_) {
                    throw Exception('Failed to fetch data'); // 模拟异常
                  })
                  .catchError((e) {
                    print('Caught an exception: $e');
                  });
            }
          
            void main() async {
              await fetchData();
              print('Done');
            }
          

          4.3,在多个 Future 中处理异常

            import 'dart:async';
          
            Future<void> task1() async {
              await Future.delayed(Duration(seconds: 1));
              throw Exception('Error in task 1');
            }
          
            Future<void> task2() async {
              await Future.delayed(Duration(seconds: 2));
              throw Exception('Error in task 2');
            }
          
            void main() async {
              try {
                await Future.wait([task1().catchError((e) {
                  print('Caught an exception in task 1: $e');
                }), task2().catchError((e) {
                  print('Caught an exception in task 2: $e');
                })]);
              } catch (e) {
                print('Caught an exception: $e');
              }
              print('Done');
            }
          
相关推荐
我要最优解4 小时前
关于在mac中配置Java系统环境变量
java·flutter·macos
江上清风山间明月2 天前
Flutter开发的应用页面非常多时如何高效管理路由
android·flutter·路由·页面管理·routes·ongenerateroute
Zsnoin能2 天前
flutter国际化、主题配置、视频播放器UI、扫码功能、水波纹问题
flutter
早起的年轻人2 天前
Flutter CupertinoNavigationBar iOS 风格导航栏的组件
flutter·ios
HappyAcmen2 天前
关于Flutter前端面试题及其答案解析
前端·flutter
coooliang2 天前
Flutter 中的单例模式
javascript·flutter·单例模式
coooliang2 天前
Flutter项目中设置安卓启动页
android·flutter
JIngles1232 天前
flutter将utf-8编码的字节序列转换为中英文字符串
java·javascript·flutter
B.-3 天前
在 Flutter 中实现文件读写
开发语言·学习·flutter·android studio·xcode
freflying11193 天前
使用jenkins构建Android+Flutter项目依赖自动升级带来兼容性问题及Jenkins构建速度慢问题解决
android·flutter·jenkins