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

Flutter中await异步函数未按预期等待,求排查错误

异步函数执行顺序问题:fnUpdateData未完成就执行_updateUI

我的按钮点击后会触发两个异步函数,但程序没等第一个函数fnUpdateData执行完,就立刻跑第二个_updateUI了。我是新手,没搞懂原理,请问错在哪?

我的代码:

Widget wgCheckUpdate(){
  if (!isUpdated) {
    return
      ElevatedButton(
        onPressed: () async {
          await fnUpdateData(); //第一个函数
          await _updateUI();    //第二个函数
        },
        child: const Text('Download'),
      );
  }
  return Container();
}

fnUpdateData() async{
  final DbHelper dbh = DbHelper();
  var DB = await dbh.db;

  const String url = 'www.mysite.com';
  String path = '';
  var hStat, hResp;
  int i;

  List<dynamic> lRows = [];
  MapEvents ME;
  MapTagList TL;

  path = '/br/BcGetEvents.php';
  Uri webaddr = Uri.http(url, path);

  http.get(webaddr).then((response) async {
    hStat = response.statusCode;
    hResp = response.body;

    lRows = jsonDecode(hResp);

    if (lRows.isNotEmpty) {
      await dbh.fnClearTable('tsmBcEvents');
    }

    for (i = 0; i < lRows.length; i++) {
      ME = MapEvents.fromMap(lRows[i]);
      DB.insert('tsmBcEvents', ME.toMap());
    }

  }).catchError((error){
    hStat = -1;
    hResp = error.toString();
  });

  path = '/br/BcGetTagList.php';
  webaddr = Uri.http(url, path);

  http.get(webaddr).then((response) async {
    hStat = response.statusCode;
    hResp = response.body;

    lRows = jsonDecode(hResp);

    if (lRows.isNotEmpty) {
      await dbh.fnClearTable('tsmBcTagList');
    }

    for (i = 0; i < lRows.length; i++) {
      TL = MapTagList.fromMap(lRows[i]);
      DB.insert('tsmBcTagList', TL.toMap());
    }

    final prefs = await SharedPreferences.getInstance();
    prefs.setBool('isUpdated', true);
  }).catchError((error){
    hStat = -1;
    hResp = error.toString();
  });
}

我查过资料,看到的示例都是await firstFunction(); await secondFunction();这种写法应该生效,但我的情况不对。


错误原因:

你在fnUpdateData里用了.then()链式调用,但没有等待这些异步操作完成。async函数里如果有未被await的Future,函数会直接继续执行后续代码,不会等待.then()里的逻辑完成,导致fnUpdateData本身提前结束,所以外层的await fnUpdateData()会提前放行,直接执行_updateUI。

简单说:你在fnUpdateData里发起了两个http.get请求,但没等它们的回调完成,函数就已经返回了,外层的await自然等不到它真正执行完。

修正方案:

把.then()换成await写法,确保每个异步操作都被等待,这样fnUpdateData会直到所有逻辑完成后才结束:

fnUpdateData() async{
  final DbHelper dbh = DbHelper();
  var DB = await dbh.db;

  const String url = 'www.mysite.com';
  String path = '';
  var hStat, hResp;
  int i;

  List<dynamic> lRows = [];
  MapEvents ME;
  MapTagList TL;

  path = '/br/BcGetEvents.php';
  Uri webaddr = Uri.http(url, path);

  try {
    final response = await http.get(webaddr);
    hStat = response.statusCode;
    hResp = response.body;

    lRows = jsonDecode(hResp);

    if (lRows.isNotEmpty) {
      await dbh.fnClearTable('tsmBcEvents');
    }

    for (i = 0; i < lRows.length; i++) {
      ME = MapEvents.fromMap(lRows[i]);
      DB.insert('tsmBcEvents', ME.toMap());
    }
  } catch (error) {
    hStat = -1;
    hResp = error.toString();
  }

  path = '/br/BcGetTagList.php';
  webaddr = Uri.http(url, path);

  try {
    final response = await http.get(webaddr);
    hStat = response.statusCode;
    hResp = response.body;

    lRows = jsonDecode(hResp);

    if (lRows.isNotEmpty) {
      await dbh.fnClearTable('tsmBcTagList');
    }

    for (i = 0; i < lRows.length; i++) {
      TL = MapTagList.fromMap(lRows[i]);
      DB.insert('tsmBcTagList', TL.toMap());
    }

    final prefs = await SharedPreferences.getInstance();
    prefs.setBool('isUpdated', true);
  } catch (error) {
    hStat = -1;
    hResp = error.toString();
  }
}

额外优化:

如果希望两个http.get请求并行执行(同时发起,提升效率),可以用Future.wait,这样也能确保两个请求都完成后再结束fnUpdateData:

fnUpdateData() async{
  final DbHelper dbh = DbHelper();
  var DB = await dbh.db;

  const String url = 'www.mysite.com';
  var hStat, hResp;

  // 处理第一个请求的逻辑
  final processEvents = () async {
    try {
      final webaddr = Uri.http(url, '/br/BcGetEvents.php');
      final response = await http.get(webaddr);
      hStat = response.statusCode;
      hResp = response.body;

      final lRows = jsonDecode(hResp);
      if (lRows.isNotEmpty) {
        await dbh.fnClearTable('tsmBcEvents');
      }

      for (var row in lRows) {
        final ME = MapEvents.fromMap(row);
        DB.insert('tsmBcEvents', ME.toMap());
      }
    } catch (error) {
      hStat = -1;
      hResp = error.toString();
    }
  };

  // 处理第二个请求的逻辑
  final processTagList = () async {
    try {
      final webaddr = Uri.http(url, '/br/BcGetTagList.php');
      final response = await http.get(webaddr);
      hStat = response.statusCode;
      hResp = response.body;

      final lRows = jsonDecode(hResp);
      if (lRows.isNotEmpty) {
        await dbh.fnClearTable('tsmBcTagList');
      }

      for (var row in lRows) {
        final TL = MapTagList.fromMap(row);
        DB.insert('tsmBcTagList', TL.toMap());
      }

      final prefs = await SharedPreferences.getInstance();
      prefs.setBool('isUpdated', true);
    } catch (error) {
      hStat = -1;
      hResp = error.toString();
    }
  };

  // 等待两个并行任务全部完成
  await Future.wait([processEvents(), processTagList()]);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 07:10:21