MST

星途 面试题库

面试题:Flutter Future网络请求队列的优化与异常处理

在构建Flutter应用的网络请求队列时,如何对请求队列进行优化以提高效率,比如在请求并发数、缓存策略上进行考虑?同时,在请求过程中出现网络异常时,如何优雅地处理并保证队列的正常执行?请详细阐述实现思路及关键代码片段。
25.0万 热度难度
前端开发Flutter

知识考点

AI 面试

面试题答案

一键面试

请求并发数优化

  1. 实现思路
    • 使用DartIsolatecompute函数来实现多任务并发执行。对于网络请求,Flutterhttp库本身支持异步操作。可以利用Future.wait结合一个List<Future>来控制并发数量。通过创建一个固定大小的请求池,当有新请求进入队列时,如果请求池未满,则立即执行请求;如果已满,则等待池中有请求完成后再执行新请求。
  2. 关键代码片段
import 'dart:async';
import 'package:http/http.dart' as http;

// 控制并发数
const int concurrentLimit = 5; 

Future<List<http.Response>> sendRequests(List<Uri> urls) async {
  List<Future<http.Response>> futures = [];
  List<http.Response> responses = [];
  int index = 0;

  while (index < urls.length) {
    int endIndex = index + concurrentLimit;
    if (endIndex > urls.length) {
      endIndex = urls.length;
    }
    List<Uri> subUrls = urls.sublist(index, endIndex);
    List<Future<http.Response>> subFutures = subUrls.map((url) => http.get(url)).toList();
    futures.addAll(subFutures);
    List<http.Response> subResponses = await Future.wait(subFutures);
    responses.addAll(subResponses);
    index = endIndex;
  }
  return responses;
}

缓存策略优化

  1. 实现思路
    • 可以使用内存缓存和磁盘缓存相结合的方式。在内存中,使用Map来存储请求的结果,每次发起请求前先检查内存缓存中是否有对应的结果。对于磁盘缓存,可以使用shared_preferences(简单数据存储)或更复杂的数据库如sqflite(适用于较大数据量)。设置缓存的过期时间,当缓存过期后重新发起网络请求并更新缓存。
  2. 关键代码片段
    • 内存缓存示例
Map<String, dynamic> inMemoryCache = {};

Future<dynamic> getWithCache(Uri url) async {
  if (inMemoryCache.containsKey(url.toString())) {
    return inMemoryCache[url.toString()];
  }
  http.Response response = await http.get(url);
  inMemoryCache[url.toString()] = response;
  return response;
}
  • 磁盘缓存示例(使用shared_preferences
import 'package:shared_preferences/shared_preferences.dart';

Future<dynamic> getWithDiskCache(Uri url) async {
  SharedPreferences prefs = await SharedPreferences.getInstance();
  String cachedResponse = prefs.getString(url.toString());
  if (cachedResponse != null) {
    return cachedResponse;
  }
  http.Response response = await http.get(url);
  prefs.setString(url.toString(), response.body);
  return response;
}

网络异常处理及队列正常执行

  1. 实现思路
    • 对于每个网络请求,使用try - catch块捕获异常。当出现异常时,记录异常信息,并将请求重新加入队列等待重试。可以设置重试次数限制,达到限制次数后放弃重试并将异常信息返回给调用者。为了保证队列正常执行,可以使用StreamStreamController来管理请求队列,在异常处理时,确保队列的状态能够正确更新。
  2. 关键代码片段
import 'dart:async';
import 'package:http/http.dart' as http;

class RequestQueue {
  final StreamController<Uri> _queueController = StreamController<Uri>();
  final int maxRetries = 3;

  RequestQueue() {
    _queueController.stream.listen((Uri url) async {
      int retryCount = 0;
      while (retryCount < maxRetries) {
        try {
          http.Response response = await http.get(url);
          // 处理响应
          print('Request to $url successful: ${response.statusCode}');
          break;
        } catch (e) {
          retryCount++;
          print('Request to $url failed, retry $retryCount: $e');
          if (retryCount == maxRetries) {
            print('Max retries reached for $url, giving up.');
          }
        }
      }
    });
  }

  void addRequest(Uri url) {
    _queueController.sink.add(url);
  }

  void dispose() {
    _queueController.close();
  }
}

// 使用示例

void main() {
  RequestQueue queue = RequestQueue();
  queue.addRequest(Uri.parse('https://example.com/api'));
  // 用完后记得释放资源
  queue.dispose();
}