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
相关产品推荐
相关产品推荐

