注册

【 Flutter 极限测试】连续 1000000 次 setState 会怎么样

测试描述

可能很多人会认为,每次的 State#setState 都会触发当前状态类的 build 方法重新构建。但真的是这样吗,你真的了解 Flutter 界面的更新流程吗?

本篇文章将做一个极限测试,看一下连续触发 1000000setState 会发生什么?是连续触发 1000000 次屏幕更新,导致界面卡死,还是无事发生?用你的眼睛来见证吧!


1、测试代码说明

如下所示,在默认案例基础上添加了两个蓝色文字,点击时分别触发如下的 _increment1_setState1000000 。其中 _setState1000000 是遍历执行 1000000setState

022e398a23624d9eac9126932dba44e8~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp

void _increment1() {
 setState(() {
   _counter++;
});
}

void _setState1000000() {
 for (int i = 0; i < 1000000; i++) {
   setState(() {
     _counter++;
  });
}
}

2、运行结果

如下是在 profile 模式下,网页调试工具中的测试结果。可以看出即使连续触发了 1000000 次的 steState ,也不会有 1000000 次的帧触发来更新界面。也就是说,并非每次的 steState 方法触发时,都会进行重新构建,所以,你真的懂 State#steState 吗?

e5610b9b60b5417dbf0ac55d21b955e8~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp


3. 源码调试分析

如下,在 State#setState 源码中可以看出,它只做了两件事:

  • 触发入参回调 fn 。

  • 执行持有元素的 markNeedsBuild 方法。

27b4014fb2fe47448e0622f30c6102d0~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp

这里 1121 行的 fn() 做了什么,不用多说了吧。就是 setState 入参的那个自加方法。

97e38083927749d0993b6aa40576c716~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp


此时该 State 中持有的 _element 对象类型是 StatefulEmement ,也就是 MyHomePage 组件创建的元素。

37a1d8398f43451fa4c7040c4fea2c93~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp


Elememt#markNeedsBuild 方法中没有一个非常重要的判断,那就是下面 4440 行 中,如果 dirty 已经是 true 时,则直接返回,不会执行接下来的方法。如果 dirtyfalse ,那接下来会置为 true

另外,owner.scheduleBuildFor 用于收集脏元素,以及申请新帧的触发。这就是为什么连续执行 1000000stateState 时,该元素不会加入脏表 1000000 次,不会触发 1000000 帧的原因。

7c2e5cf8c9ae4e49b06b704f432df69c~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp

总的来说, State#setState 的核心作用就是把持有的元素标脏申请新帧调度。而只有新帧到来,执行完构建之后,元素的 dirty 才会置为 false 。也就是说,两帧之间,无论调用多少次 setState ,都只会触发一次, 元素标脏申请新帧调度 。这就是为什么连续触发 1000000 次,并无大事发生的原因。


作者:张风捷特烈
来源:https://juejin.cn/post/7091471603774521352

0 个评论

要回复文章请先登录注册