React中最神奇的部分莫过于虚拟DOM,以及其高效的Diff算法,为这个框架如此流行的基石。在React中,构建UI界面的思路是由当前状态决定界面。前后两个状态就对应两套界面,然后由React来比较两个界面的区别,这就需要对DOM树进行Diff算法分析。即给定任意两棵树,找到最少的转换步骤。但是标准的的Diff算法复杂度需要O(n^3),这显然无法满足性能要求。要达到每次界面都可以整体刷新界面的目的,势必需要对算法进行优化。这看上去非常有难度,然而Facebook工程师却做到了,他们结合Web界面的特点做出了两个简单的假设,使得Diff算法复杂度直接降低到O(n)。
android support-library 24.2.0版本提供了一个新的 DiffUtil
类可以计算两个集合之间的差异,并分派适合 RecyclerView.Adapter
使用的更新操作列表。DiffUtil使用的是" Eugene W. Myers's difference"算法。来看看这个算法的有啥优势
该算法为空间优化, 使用 o (n) 空间来查找两个列表之间的加法和移除操作的最小数目。它有 o (n + D^2) 预期的时间性能, 其中 d 是编辑长度。
如果启用了移动检测, 则需要额外的 o (n ^ 2) 时间, 其中 n 是添加和移除项的总数。如果您的列表已按相同的约束 (例如, 为list创建的时间戳) 排序, 则可以禁用移动检测以提高性能。
算法的实际运行时显著取决于列表中的更改数和比较方法的开销。下面是一些平均运行时间, 供参考: (测试列表由随机 uuid 字符串组成, 测试运行在与 m 的连结5X 上)
百项和十个修改: avg: 0.39 毫秒, 中值: 100 ms
百项和百修改: 中位数: ms
百项和百修改不移动: 2.09 毫秒, 中值: 2.06 毫秒
1000项和50修改: avg: 4.67 毫秒, 中值: 4.59 毫秒
1000项和50修改没有移动: avg: 中中值: ms
1000项目和200修改: 27.07 毫秒, 中值: 26.92 毫秒
1000项和200修改不移动: 13.54 毫秒, 中值: 13.36 毫秒
由于实现约束, 列表的最大大小可以是两大。
哈哈,好厉害啊