Flutter中Future.wait触发setState异常,嵌套microtask正常的原因?
核心原因:initState阶段的执行时机限制
在initState方法执行期间,当前Widget还未完成挂载到Widget树的流程,此时调用notifyListeners()会触发依赖该ChangeNotifier的Widget执行重建操作,但Flutter框架不允许在Widget构建/初始化过程中同步触发重建,否则会抛出setState() or markNeedsBuild()异常。
直接调用Future.wait报错的原因
当你直接执行:
Future.wait([ someFuncA(), someFuncB(), ]);
someFuncA()和someFuncB()作为异步函数,其内部的同步代码部分会立即执行——也就是isLoadingA = true;和notifyListeners();这两行会在initState的同步执行流程中直接运行,此时Widget还处于初始化阶段,触发重建操作违反了框架的执行规则,因此抛出异常。
包裹Future.microtask后正常的原因
Future.microtask的作用是将传入的回调函数加入微任务队列,微任务队列会在当前所有同步代码执行完毕后(也就是initState执行完成后)才会被处理。此时Widget已经完成初始化流程,处于可以安全触发重建的状态,所以notifyListeners()可以正常执行,不会抛出异常。
不管是并行的写法:
Future.wait([ Future.microtask(() => someFuncA()), Future.microtask(() => someFuncB()), ]);
还是串行的写法:
Future.microtask(()async{ await someFuncA(); await someFuncB(); });
本质都是把notifyListeners()的执行时机推迟到了initState完成之后,避开了框架的限制。
关于Future.wait与Future.microtask的差异
Future.wait本身只是用来等待多个异步任务完成的工具,它不会改变任务本身的执行时机;而Future.microtask是用来控制任务的执行时机——将任务推迟到当前同步代码块执行完毕后立即执行(早于Event队列的任务)。
你想要并行执行提升性能的需求,用Future.wait搭配Future.microtask的写法是完全合理的,既保留了并行执行的优势,又避开了initState阶段的限制。
内容的提问来源于stack exchange,提问作者samedhrmn

