You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Future.timeout仅生效一次:重试时立即触发TimeoutException

问题分析

你遇到的问题核心原因是复用了同一个Future实例:当第一次调用widget.onConfirm().timeout(...)超时后,这个Future已经进入失败状态(抛出TimeoutException),后续重试时如果仍使用这个已完成的Future,timeout会直接返回之前的失败结果,不会重新启动计时器,所以看起来“立即抛出超时异常”。

解决方案

关键是每次重试都创建新的Future实例——也就是每次触发重试时,重新调用widget.onConfirm()发起新的异步请求,而非复用旧的Future。

手动触发重试的修正代码

Future<void> _asyncLogic() async {
  try {
    // 每次都调用widget.onConfirm()获取新的Future,避免复用旧实例
    await widget.onConfirm().timeout(const Duration(seconds: 2));
  } on TimeoutException {
    print('超时了');
    setState(() {
      _future = null;
    });
  } catch (error) {
    print(error);
    setState(() {
      _future = null;
    });
  }
}

void _handleConfirm() => setState(() {
      // 每次点击都重新生成_asyncLogic的Future,确保内部是新的异步任务
      _future = _asyncLogic();
    });

自动重试的实现(可选)

如果需要超时后自动重试,可在超时逻辑里循环发起新请求,同时建议添加重试间隔与最大次数限制:

Future<void> _asyncLogic({int maxRetries = 3}) async {
  int retryCount = 0;
  bool shouldRetry = true;

  while (shouldRetry && retryCount < maxRetries) {
    try {
      await widget.onConfirm().timeout(const Duration(seconds: 2));
      shouldRetry = false; // 请求成功,终止重试
    } on TimeoutException {
      retryCount++;
      print('第$retryCount次超时,准备重试');
      // 重试前添加短暂延迟,避免频繁请求
      await Future.delayed(const Duration(milliseconds: 500));
    } catch (error) {
      print('请求出错:$error');
      shouldRetry = false; // 非超时错误,终止重试
      setState(() {
        _future = null;
      });
    }
  }

  if (retryCount >= maxRetries) {
    print('达到最大重试次数,停止请求');
    setState(() {
      _future = null;
    });
  }
}
关键注意点
  • 永远不要复用已完成(成功/失败)的Future实例,每次异步任务都要创建新的Future。
  • 自动重试场景下,务必设置最大重试次数与重试间隔,避免无限循环或对服务端造成压力。

内容的提问来源于stack exchange,提问作者pacifica94

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 07:35:07