【问题标题】:Await future for a specific time在特定时间等待未来
【发布时间】:2024-01-30 15:50:02
【问题描述】:

您将如何在特定时间内等待未来的响应?

说,我们在关闭 http 请求之前发出一个 http post 请求并等待它的响应,但是,我们只等待 3 秒,否则我们关闭请求。

您将如何实现这一目标?

类似

Future makePostReq() async{
  .... 

  await http response for 3 secs

  .... 

 if(response) {
  ... Do something with it
 }

 Http.close

} 

【问题讨论】:

    标签: asynchronous dart async-await flutter future


    【解决方案1】:

    您可以使用Future.any 构造函数来设置竞争条件

    final result = await Future.any([
      Future.value(42),
      Future.delayed(const Duration(seconds: 3))
    ]);
    

    你也可以使用Future.timout方法

    final result = await Future.value(42).timeout(const Duration(seconds: 3));
    

    【讨论】:

    • 会试一试。 42有什么用?
    • @RémiRousselet 很抱歉回答一个老问题:这两种解决方案有什么区别?它们还可行吗?
    • @GiacomoM 第一个基本上尝试解析 2 个期货并返回第一个完成的期货。第二个启动一个计时器,如果到那时未来还没有完成,它会抛出,或者如果你包含一个onTimeout 函数,它将返回那个值。我会使用第二个,因为它是专门为此目的而设计的,但它们都同样有效。
    • @ThinkDigital 不,我不明白在这个具体的例子中究竟是什么返回了声明const Duration(seconds: 3)
    • 42 是大问题的答案;关于生命、宇宙和一切的意义,所以,它就像一个非常重要的未来。就道格拉斯·亚当斯而言。
    【解决方案2】:

    Future.any([asyncfunc, ...])

    这是使用 Remi 的 Future.any 解决方案的示例,其中将使用首先返回的未来。另一个被丢弃。

    因此,第一个未来是您的数据收集/慢速功能,另一个是您的通话时间过长时的后备。

        dynamic result = await Future.any([
          getData(fakeDelay: seconds), // ← hope this returns first
          timeoutAfter(sec: timeout, onTimeout: () => 'Timed Out!', ) // ← waited too long, do this
        ]);
    

    Flutter 页面中的示例

    这是 Flutter 页面的复制/粘贴示例:

    (查看调试/运行输出窗口中的消息)

    import 'package:flutter/material.dart';
    
    class FutureTimeoutPage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('Future or Timeout Page'),
          ),
          body: FutureAnyExample(),
        );
      }
    }
    
    class FutureAnyExample extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('Complete before timeout or timeout:'),
            SizedBox(height: 30,),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                ElevatedButton(onPressed: () => getDataOrTimeout(seconds: 1, timeout: 3),
                    child: Text('In Time')),
                ElevatedButton(onPressed: () => getDataOrTimeout(seconds: 5, timeout: 3),
                    child: Text('Too Slow'))
              ],
            )
          ],
        );
      }
    
      Future<void> getDataOrTimeout({int seconds, int timeout}) async {
        /// In Future.any, put as many async functions as you need.
        /// Whichever completes first, will be returned. All others are discarded
        dynamic result = await Future.any([
          getData(fakeDelay: seconds), // ← hope this returns first
          timeoutAfter(sec: timeout, onTimeout: () => 'Timed Out!', ) // ← waited too long, do this
        ]);
    
        print(result);
      }
    
      /// Mock of a long-running operation like getting DB data, or API call
      Future<String> getData({int fakeDelay}) async {
        return Future.delayed(Duration(seconds: fakeDelay), () => 'Data returned!');
      }
    
      /// Do this in case my long-running op takes too long
      /// Can run a function or just return some message
      Future<dynamic> timeoutAfter({int sec, Function() onTimeout}) async {
        return Future.delayed(Duration(seconds: sec), onTimeout);
      }
    }
    

    【讨论】:

      【解决方案3】:

      你可以很容易地做到这一点

      try {
             var response = await Http.get("YourUrl").timeout(const Duration(seconds: 3));
             if(response.statusCode == 200){
                print("Success");
             }else{
                print("Something wrong");
             }
       } on TimeoutException catch (e) {
           print('Timeout');
       } on Error catch (e) {
           print('Error: $e');
       }
      

      此示例将超时设置为 3 秒。如果已经 3 秒没有收到响应,则会抛出 TimeoutException

      导入这个:

      import 'package:http/http.dart' as Http;
      import 'dart:async';
      

      【讨论】:

      • 我收到错误错误:'TimeoutException' 不是类型。在 TimeoutException 上捕获 (e) {
      • 您需要添加import 'dart:async';