MST

星途 面试题库

面试题:Flutter中异步/await模式下如何处理多个并发任务

在Flutter项目中,假设有多个需要并发执行的异步任务,例如同时从多个API获取数据。请描述如何使用异步/await模式结合合适的方法来实现,并说明可能会遇到的问题以及如何解决。
47.4万 热度难度
前端开发Flutter

知识考点

AI 面试

面试题答案

一键面试

实现方式

  1. 使用Future.wait:在Flutter中,可以使用Future.wait方法来并发执行多个异步任务。Future.wait接受一个Future对象的列表,并返回一个新的Future,这个新的Future在所有传入的Future都完成时完成。
Future<List<dynamic>> fetchData() async {
  List<Future<dynamic>> futures = [
    // 假设这是从不同API获取数据的异步函数
    fetchDataFromAPI1(), 
    fetchDataFromAPI2(), 
    fetchDataFromAPI3()
  ];
  return Future.wait(futures);
}

Future<dynamic> fetchDataFromAPI1() async {
  // 模拟从API1获取数据
  await Future.delayed(const Duration(seconds: 2));
  return "Data from API1";
}

Future<dynamic> fetchDataFromAPI2() async {
  // 模拟从API2获取数据
  await Future.delayed(const Duration(seconds: 3));
  return "Data from API2";
}

Future<dynamic> fetchDataFromAPI3() async {
  // 模拟从API3获取数据
  await Future.delayed(const Duration(seconds: 1));
  return "Data from API3";
}
  1. 使用async/await处理结果:在调用fetchData函数时,可以使用async/await来等待所有任务完成并处理结果。
void main() async {
  List<dynamic> results = await fetchData();
  results.forEach((element) {
    print(element);
  });
}

可能遇到的问题及解决方法

  1. 某个任务失败:如果Future.wait中的任何一个Future抛出异常,整个Future.wait都会失败并抛出该异常。
    • 解决方法:可以使用try-catch块来捕获异常,并对失败的任务进行处理。例如,可以记录错误日志或者提供默认值。
Future<List<dynamic>> fetchData() async {
  List<Future<dynamic>> futures = [
    fetchDataFromAPI1(), 
    fetchDataFromAPI2(), 
    fetchDataFromAPI3()
  ];
  try {
    return await Future.wait(futures);
  } catch (e) {
    // 记录错误日志
    print('An error occurred: $e');
    // 返回默认值
    return List.filled(futures.length, null);
  }
}
  1. 资源消耗问题:如果并发的任务过多,可能会导致资源消耗过大,如内存、网络资源等。
    • 解决方法:可以限制并发任务的数量。例如,可以使用StreamStreamController来实现一个任务队列,控制同时执行的任务数量。
import 'dart:async';

class TaskQueue {
  final int maxConcurrentTasks;
  final Queue<Future<dynamic> Function()> taskQueue = Queue();
  final List<Future<dynamic>> activeTasks = [];
  final StreamController<List<dynamic>> _resultController = StreamController();
  Stream<List<dynamic>> get results => _resultController.stream;

  TaskQueue(this.maxConcurrentTasks);

  void addTask(Future<dynamic> Function() task) {
    taskQueue.add(task);
    _startNextTask();
  }

  void _startNextTask() {
    while (activeTasks.length < maxConcurrentTasks && taskQueue.isNotEmpty) {
      final task = taskQueue.removeFirst();
      final future = task();
      activeTasks.add(future);
      future.then((value) {
        activeTasks.remove(future);
        _startNextTask();
        _resultController.add([...activeTasks, value]);
      }).catchError((error) {
        activeTasks.remove(future);
        _startNextTask();
        _resultController.addError(error);
      });
    }
  }

  void close() {
    _resultController.close();
  }
}

使用示例:

void main() async {
  final taskQueue = TaskQueue(2);
  taskQueue.addTask(fetchDataFromAPI1);
  taskQueue.addTask(fetchDataFromAPI2);
  taskQueue.addTask(fetchDataFromAPI3);

  taskQueue.results.listen((results) {
    print('Current results: $results');
  }, onError: (error) {
    print('Error: $error');
  }, onDone: () {
    print('All tasks completed');
    taskQueue.close();
  });
}