预加载

预加载 是一种提高数据读取性能的工具。通过在命令中批量调用预加载,可以显著缩短读取数据的时长,提高性能。

玩家数据

这是一个简单的例子:
for (var 玩家id of 玩家id列表) {
 var 玩家变量 = 查找玩家(玩家id);
 玩家变量.发送未读消息(玩家.名字 + '的金钱:' + 玩家.属性.金钱 + ',所在位置:' + 玩家.位置);
}
在这段代码中,我们向 玩家id列表 中的所有玩家依次发送未读消息。其中加载了玩家的名字、属性和位置数据。
在循环中,代码要依次读取每个玩家的名字、属性和位置,这导致代码的运行时长变长。
而通过玩家.预加载.xxx,可以预加载玩家数据。例如:
for (var 玩家id of 玩家id列表) {
  var 玩家 = 查找玩家(玩家id);
  玩家.预加载.名字;
  玩家.预加载.属性.金钱;
  玩家.预加载.位置;
}

// 预加载玩家的数据后,数据读取性能会显著提升
for (var 玩家id of 玩家id列表) {
 var 玩家 = 查找玩家(玩家id);
 玩家变量.发送未读消息(玩家.名字 + '的金钱:' + 玩家.属性.金钱 + ',所在位置:' + 玩家.位置);
}
在这个例子中,我们在读取玩家数据前,先调用预加载。“预加载”用于告诉系统,我们将要使用这些数据。系统会数据被使用前,一次性读取这些数据,后续使用这些数据时,则不需要依次加载它们,减少了运行时长。

数据库

这是一个关于数据库的例子:
var 总金钱 = 0;
for (var 玩家id of 玩家id列表) {
 总金钱 += 数据.(['玩家', 玩家id, '金钱']);
}
在这段代码中,我们希望计算 玩家id列表 中的所有玩家的总金钱,其中读取了数据库的特定路径。
在循环中,数据库要依次读取每个玩家所对应的路径。而通过数据.预加载.读([xxx]),可以预加载数据库特定路径。例如:
for (var 玩家id of 玩家id列表) {
  数据.预加载.(['玩家', 玩家id, '金钱']);
}

// 预加载数据库后,数据读取性能会显著提升
var 总金钱 = 0;
for (var 玩家id of 玩家id列表) {
 总金钱 += 数据.(['玩家', 玩家id, '金钱']);
}
这时,数据库的读取性能将得到显著提升。

性能

预加载可以显著提升数据批量读取时的性能。
例如,下面这段代码大概需要执行 200~300 毫秒。
for (let i = 0; i < 500; i++) {
    数据.(['测试路径', i]);
}
经过预加载优化后,这段代码用时 50~70 毫秒。
for (let i = 0; i < 500; i++) {
    数据.预加载.(['测试路径', i]);
}

for (let i = 0; i < 500; i++) {
    数据.(['测试路径', i]);
}
由此可见,预加载对性能的优化是非常明显的。后续,随着 Realm 的不断更新,未来还有可能进一步缩短这段代码的运行时长。

使用场景

从上面的例子可以看出,预加载适合有批量数据读取的场景。例如,在组件中显示列表、批量读取用户的信息等。
需要注意的是,预加载只有在连续调用的情况下才会提高性能,下面这种代码是无法提高性能的:
// 错误示例
var 总金钱 = 0;
for (var 玩家id of 玩家id列表) {
 数据.预加载.(['玩家', 玩家id, '金钱']);
 总金钱 += 数据.(['玩家', 玩家id, '金钱']);
}
像上述代码 预加载.读 -> -> 预加载.读 -> ... 这么依次调用是错误的。同理,如果只是读取一个数据,那么预加载这个数据也不会有性能提升。
此外,预加载命令没有返回值,不能直接使用:
// 错误示例
var 总金钱 = 0;
for (var 玩家id of 玩家id列表) {
 总金钱 += 数据.预加载.(['玩家', 玩家id, '金钱']);
}
“预加载”的效果会在脚本运行结束前一直生效,因此每个数据只需要预加载一次。例如,组件顶部的变量代码执行了“预加载”,后续的变量代码、子组件都会生效。在函数中的“预加载”也会在函数外生效。条件、动作、单次延迟执行、对外接口等脚本也同样适用。
“预加载”可以被重复调用,不会有额外影响。但循环代码本身具有一定的运行时长,因此最好避免重复调用“预加载”。
如果已经通过普通命令加载了数据,调用相应数据的“预加载”则不会有额外效果。
在使用“预加载”时,可以先对代码性能进行测试,确保使用“预加载”后有性能提升,避免不必要的冗余代码。