MST
星途 面试题库

面试题:Flutter中Future与async/await的错误处理及优化

假设你在Flutter应用中使用Future和async/await进行多个异步任务的并发执行,可能会出现网络错误等异常情况。请描述如何优雅地处理这些错误,并且在出现错误时如何保证其他任务的继续执行或进行适当的回滚操作?同时,阐述如何优化这种并发任务的性能,比如设置合理的并发数量。
50.0万 热度难度
前端开发Flutter

知识考点

AI 面试

面试题答案

一键面试
  1. 错误处理
    • 使用try - catch块包裹每个await语句,以便捕获单个任务中的异常。例如:
    Future<void> performTasks() async {
      List<Future<void>> tasks = [task1(), task2(), task3()];
      for (var task in tasks) {
        try {
          await task;
        } catch (e) {
          // 处理错误,如记录日志
          print('Error occurred in task: $e');
        }
      }
    }
    Future<void> task1() async {
      // 模拟异步任务
      await Future.delayed(const Duration(seconds: 1));
      // 可能会抛出异常
      throw Exception('Task 1 error');
    }
    Future<void> task2() async {
      await Future.delayed(const Duration(seconds: 1));
      print('Task 2 completed');
    }
    Future<void> task3() async {
      await Future.delayed(const Duration(seconds: 1));
      print('Task 3 completed');
    }
    
    • 另一种方式是使用Future.wait结合catchErrorFuture.wait可以并发执行多个Future,并返回一个新的Future,当所有Future都完成时,新的Future完成。catchError可以捕获其中任何一个Future抛出的异常。
    Future<void> performTasks() async {
      List<Future<void>> tasks = [task1(), task2(), task3()];
      try {
        await Future.wait(tasks, eagerError: true).catchError((e) {
          // 处理错误,如记录日志
          print('Error occurred in task: $e');
        });
      } catch (e) {
        // 这里也可以捕获异常,但一般在catchError中处理就好
        print('Another error handling: $e');
      }
    }
    Future<void> task1() async {
      await Future.delayed(const Duration(seconds: 1));
      throw Exception('Task 1 error');
    }
    Future<void> task2() async {
      await Future.delayed(const Duration(seconds: 1));
      print('Task 2 completed');
    }
    Future<void> task3() async {
      await Future.delayed(const Duration(seconds: 1));
      print('Task 3 completed');
    }
    
  2. 回滚操作
    • 对于有状态变化的任务,在任务执行前记录初始状态,若任务执行过程中抛出异常,恢复到初始状态。例如,在数据库操作中,若插入数据失败,需要回滚插入操作。
    Future<void> insertData() async {
      var initialData = await fetchData();
      try {
        await database.insert('table', {'data': 'new data'});
      } catch (e) {
        // 回滚操作,如删除刚插入的数据(如果有部分插入成功)或恢复到初始数据状态
        await database.delete('table', where: {'data': 'new data'});
        // 或者恢复到初始数据
        await database.update('table', initialData);
      }
    }
    
  3. 优化并发任务性能
    • 设置合理的并发数量:使用dart:async库中的StreamStreamController来实现有限并发。例如,可以使用Stream来管理任务队列,并且每次只处理固定数量的任务。
    Future<void> performTasks() async {
      int maxConcurrent = 2;
      List<Future<void>> tasks = [task1(), task2(), task3(), task4()];
      StreamController<Future<void>> controller = StreamController<Future<void>>();
      tasks.forEach((task) => controller.add(task));
      controller.close();
      List<Future<void>> activeTasks = [];
      await for (var task in controller.stream) {
        activeTasks.add(task);
        if (activeTasks.length >= maxConcurrent) {
          await Future.any(activeTasks).then((value) {
            activeTasks.remove(value);
          });
        }
      }
      await Future.wait(activeTasks);
    }
    Future<void> task1() async {
      await Future.delayed(const Duration(seconds: 1));
      print('Task 1 completed');
    }
    Future<void> task2() async {
      await Future.delayed(const Duration(seconds: 1));
      print('Task 2 completed');
    }
    Future<void> task3() async {
      await Future.delayed(const Duration(seconds: 1));
      print('Task 3 completed');
    }
    Future<void> task4() async {
      await Future.delayed(const Duration(seconds: 1));
      print('Task 4 completed');
    }
    
    • 缓存结果:如果某些异步任务的结果是固定不变或者变化频率很低的,可以缓存这些结果,避免重复执行任务。例如,使用Map来缓存Future的结果。
    Map<String, Future<dynamic>> cache = {};
    Future<dynamic> getCachedData(String key) {
      if (!cache.containsKey(key)) {
        cache[key] = performAsyncTask();
      }
      return cache[key]!;
    }
    Future<dynamic> performAsyncTask() async {
      await Future.delayed(const Duration(seconds: 1));
      return 'result';
    }