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

Alfred框架异步处理函数执行顺序错乱,如何实现预期执行逻辑?

问题原因

Dart 中的 Timer.periodic 属于非阻塞异步 API,调用后会立即返回,不会等待定时器回调内的异步逻辑执行完成。虽然你给 complexTendexAPIRequest 加了 async 修饰,但函数在创建完定时器后就直接结束返回了,外层的 await complexTendexAPIRequest(...) 并没有真正等待轮询、拉取结果、写文件的完整流程执行完成,因此会出现输出顺序错乱的问题。

修复方案

方案1:用 Completer 封装 Timer 逻辑(保留 Timer 实现)

可以通过 Completer 包装整个轮询流程,只有当所有操作执行完成后再标记流程结束,外层的 await 就能正常等待整个函数执行完成:

import 'dart:async';

// 明确声明返回 Future<void>
Future<void> complexTendexAPIRequest(Map<String, dynamic> data) async {
  print('Request: $data');
  final completer = Completer<void>();
  try {
      final response = await http.post(
        Uri.parse(COMPLEX_URL),
        headers: {'Content-Type': 'application/json', 'Authorization': 'bearer $ACCESS_TOKEN'},
        body: json.encode(data)
      );

      if(response.statusCode == 200) {
        var res = json.decode(response.body);
        int latestId = res['id'];
        String url = 'https://api.ru/v2/complex/status?id=$latestId';
        stdout.write('Waiting for "complete" status from API: ');
        Timer.periodic(Duration(seconds: 1), (timer) async {
          try {
            final response = await http.get(
              Uri.parse(url),
              headers: {'Content-Type': 'application/json', 'Authorization': 'bearer $ACCESS_TOKEN'}
            );

            var data = json.decode(response.body);
            if(data['status'] == 'completed') {
              timer.cancel();
              stdout.write('[DONE]');
              stdout.write('\nFetching result: ');
              String url = "https://api.ru/v2/complex/results?id=$latestId";
              final response = await http.get(
                Uri.parse(url),
                headers: {'Content-Type': 'application/json', 'Authorization': 'bearer $ACCESS_TOKEN'}
              );
              stdout.write('[DONE]');
              var data = prettyJson(json.decode(response.body));
              await File('result.json').writeAsString(data.toString());
              print("\nCreating dump of result: [DONE]");
              // 所有逻辑执行完成,标记结束
              completer.complete();
            }
          } catch(e) {
            timer.cancel();
            // 轮询过程出现异常,向外抛出
            completer.completeError(e);
          }
        });
        
      }
      else {
        print('[ERROR] Wrong status code for complex request. StatusCode: ${response.statusCode}');
        completer.complete();
      }
  } 
  on SocketException catch(e) {
    print('No Internet connection: $e');
    completer.completeError(e);
  } on TimeoutException catch(e) {
    print('TenderAPI Timeout: $e');
    completer.completeError(e);
  } on Exception catch(e) {
    print('Some unknown Exception: $e');
    completer.completeError(e);
  }
  // 返回 Completer 的 Future 供外层 await
  return completer.future;
}

方案2:改用 while 循环实现轮询(更简洁的方案)

这种方案不需要额外引入 Completer,本身就是顺序执行的异步逻辑,外层 await 可以直接等待整个流程结束,也是你当前已经验证可行的方案:

Future<void> complexTendexAPIRequest(Map<String, dynamic> data) async {
  print('Request: $data');
  try {
      final response = await http.post(
        Uri.parse(COMPLEX_URL),
        headers: {'Content-Type': 'application/json', 'Authorization': 'bearer $ACCESS_TOKEN'},
        body: json.encode(data)
      );

      if(response.statusCode == 200) {
        var res = json.decode(response.body);
        int latestId = res['id'];
        String statusUrl = 'https://api.ru/v2/complex/status?id=$latestId';
        stdout.write('Waiting for "complete" status from API: ');
        // while 循环轮询状态
        while(true) {
          final response = await http.get(
            Uri.parse(statusUrl),
            headers: {'Content-Type': 'application/json', 'Authorization': 'bearer $ACCESS_TOKEN'}
          );
          var statusData = json.decode(response.body);
          if(statusData['status'] == 'completed') {
            break;
          }
          // 每秒轮询一次
          await Future.delayed(Duration(seconds: 1));
        }
        stdout.write('[DONE]');
        stdout.write('\nFetching result: ');
        String resultUrl = "https://api.ru/v2/complex/results?id=$latestId";
        final resultResponse = await http.get(
          Uri.parse(resultUrl),
          headers: {'Content-Type': 'application/json', 'Authorization': 'bearer $ACCESS_TOKEN'}
        );
        stdout.write('[DONE]');
        var resultData = prettyJson(json.decode(resultResponse.body));
        await File('result.json').writeAsString(resultData.toString());
        print("\nCreating dump of result: [DONE]");
      }
      else {
        print('[ERROR] Wrong status code for complex request. StatusCode: ${response.statusCode}');
      }
  } 
  on SocketException catch(e) {
    print('No Internet connection: $e');
    rethrow;
  } on TimeoutException catch(e) {
    print('TenderAPI Timeout: $e');
    rethrow;
  } on Exception catch(e) {
    print('Some unknown Exception: $e');
    rethrow;
  }
}

以上两种方案都可以保证 print('Hello World') 和 await res.json({'data': 'ok'}) 会在 complexTendexAPIRequest 所有逻辑执行完成后再运行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 04:36:05