UI 代码的载入顺序
原文:UI_Code_Load_Order,发表于 WoWWiki
译者:流润之风
本文描述了 XML 文件解析载入行为的先后顺序,此外,也会涵盖插件和文件的载入顺序。
单个插件内的各文件
在单个插件之内(或在 FrameXML 之内),载入是按照 .toc 文件中定义的顺序线性进行的。toc 中定义的第一个文件最先被解析执行,之后是第二个,然后是第三个,依此类推。对于 XML 文件,每当执行到其中包含的 <Script file="X"/> 元素,就会去解析和执行引用的文件 X,处理完后才会接着处理后面的元素。因而,如果有以下的 toc 结构:
File1.lua File2.lua File3.xml File4.xml File5.lua
而且 File3.xml 包含了:
<Script file="FileA.lua"/> 和
<Script file="FileB.lua"/>,
File4.xml 包含了:
<Script file="FileA.lua"/> 和
<Script file="FileC.lua"/>
那么,载入/执行的顺序将会是:
- File1.lua
- File2.lua
- File3.xml
- 开始
- FileA.lua
- FileB.lua
- File3.xml 的其余部分
- File4.xml
- 开始
- FileA.lua
- FileC.lua
- File4.xml 的其余部分
- File5.lua
可以看到,我们完全能够预计到整个载入过程的先后顺序,另外,FileA.lua 执行了两次。因而,当你想在 XML 中包含 <Script> 代码时一定要谨慎。
LUA 文件的处理
lua 文件由 lua 引擎解析执行。所有的内嵌代码会马上执行(事实上,这是函数定义如何发生的方式--简单地执行)
XML文件的处理
XML 文件按元素的先后顺序进行处理
Script元素
如上文所述,<Script.../> 元素会在遇到时立即得到处理。它们只能出现在文件的开头部分,通常用于执行某些设置代码、或是包含某个 lua 文件(对于这种情况要谨慎,因为有可能会对一个 lua 文件载入多次)。
虚元素
虚框体元素在解析之后存储下来,以备后用,它们无法自我执行,不会产生任何 LUA 对象。而只是创建出一个可供以后使用的模板。虚框体的定义会在插件载入批处理过程结束时丢弃,关于批处理下面会有更详细的解释,从本质上来说,游戏登录就是一个批处理过程,游戏运行后每个 LoadOnDemand 调用(以及该调用所执行的嵌套载入)也都是独立的批处理过程。
一般元素和继承元素
所有的一般元素和继承元素按照以下步骤进行递归处理:
- 创建适当的 C++ 对象和 lua 引用(记住,不能锚固到一个尚未创建的框体上)
- 如果该框体继承自某个虚模板,那么先将这些规则应用到模板上,再继续。
- 如果该框体有子框体,那么按照子框体在 XML 文件中出现的顺序将规则应用到所有子框体上。
- 将所有脚本处理器应用到框体上
调用框体的 OnLoad 处理器.
考虑以下的结构:
<Frame name="V1" virtual="true">
<Frames>
<Frame name="$parent_V1_C1"/>
<Frame name="$parent_V1_C2"/>
</Frames>
</Frame><Frame name="V2" inherits="V1" virtual="true">
<Frames>
<Frame name="$parent_V2_C1"/>
<Frame name="$parent_V2_C2" inherits="V1"/>
</Frames>
</Frame><Frame name="F" inherits="V2">
<Frames>
<Frame name="$parent_C1" inherits="V1"/>
<Frame name="$parent_C2"/>
</Frames>
</Frame>创建/载入的顺序将会是:
- Create F
OnLoad F
插件的载入顺序
先把按需载入的插件放到一边,最先载入的是 FrameXML(它其实并不是插件,但是有着类似插件的结构和载入方式),然后是其他插件,它们按照操作系统返回的顺序进行处理(对于一般的 Windows 版本来说,也就是目录项顺序,最先放入插件目录的插件会被最先载入,如果删除了某个目录,那么会将空位保留给下一个新加入的目录。该顺序又被称为未排序顺序),并遵循以下基本原则:
- 如果插件已被载入(或正在载入),那么不再载入。
- 如果插件有未载入的依赖项,那么按这些依赖项在 .toc 中的顺序进行载入
- 如果插件有未载入、已激活、可选的依赖项,那么按这些依赖项在 .toc 中的顺序进行载入
- 如前所述,按 .toc 中的排列顺序载入各插件文件
如果有其他未载入、已激活的插件,且标记为 LoadWith 本插件(随同本插件载入),那么处理它们(处理顺序未知,我想是文件系统的自然顺序)。
按照这些规则,将所有的插件以合理的顺序进行载入,使各插件的依赖项优先载入。
按需载入的 插件
按需载入要更加复杂一些,因为它们在需要时才进行初始化,而且在插件(和所有子插件)的载入过程结束以前 Load 插件函数将保持阻塞。调用 Load 之后,遵循与上述过程相同的规则进行载入处理,而且在该过程完成之前,Load 函数不会返回。


