跳到主要内容

编译顺序说明

在 Egret 中,需使用 TypeScript 编写程序,最终编译成浏览器可读的 JavaScript。

JavaScript 是一种脚本语言,浏览器按脚本的顺序来执行。实际上浏览器会根据 <script> 标签中脚本的载入顺序来执行脚本。当某个脚本引用了一个未载入的脚本中的变量时,浏览将报出相应的错误。

一般情况下,在 Egret 项目中并不需要手动处理编译顺序,因为egret编译器已经帮助开发者处理好了。但是有一种情况是编译器不能处理的,需要手动加上 <reference> 标签来告诉编译器 项目中类的依赖关系。下面是具体的代码和解决的方法。

TypeScript详细手册参考:TypeScript Handbook(中文版)

测试依赖关系

新建一个 Egret 项目,这里使用 egret create test 创建一个 Egret 默认项目。

建立若干测试类,项目的结构如下:

如上所示,创建了一个 Test 文件夹,内部创建了 Call 文件夹,在 Call 内部创建了 TestCall.ts。同时在 Test 文件夹内创建 TestA.ts 和 TestB.ts。其余的 Main.ts 和 LoadingUI.ts 等这里用不到,在此忽略。

在 TestA.ts 中代码如下:

class  TestA  {
public static arr: Array<any\> = ["t", "e", "s", "t", "c", "a", "l", "l"];
}

TestB.ts 中代码如下:

class  TestB  {
public static testBStr: string = TestA.arr.join("");
}

这两个类都只有一个静态成员。其中 TestA 类存放了一个数组,TestB 类将这个数组的内容拼接成一个字符串并保存下来。到目前为止我们编译运行并没有发现异常。

下面在TestCall.ts 中加入对 TestB 类的调用。

class  TestCall  {
public static test: any = egret.getDefinitionByName(TestB.testBStr);
}

编译运行之后发现浏览器会报如下TestB.js:11 Uncaught ReferenceError错误:

当我们添加了 TestB.testBstr 的调用之后浏览器发现 TestA 类并没有被定义,进而导致 testBStr 这个属性页找不到了。在编译之后检查生成的 index.html 文件会发现 TestB.js 是在 TestCall.js 之前加载的,而 TestA.js 是在最后加载的。当 TestB.js 调用 TestA.js 中的文件的内容时浏览器将会报错。

上面的调用关系在代码中显然是成立的,编译器并没有报错。而编译器并没有生成正确的载入顺序,主要是因为其无法确认这种类的静态成员的互相引用的顺序。当在 TestCall.ts 中引用了TestB.ts 中的内容时自动将 TestB.js 放在 TestCall.js 之前进行加载。由于无法检测到 TestB.ts 中对 TestA.ts 的静态成员的引用,所以导致了以上情况的发生。

解决方法

这种情况解决方法是告诉编译器项目中的类的依赖关系。在 TypeScript 中,使用<reference>标签来表示引用关系。在 reference 标签中可以标记依赖文件的相对路径。所以只需要在 TestB 类之前加入如下注释即可:

///<reference path="TestA.ts" />
class  TestB  {
public static testBStr: string = TestA.arr.join("");
}

上面这种情况一般发生在静态成员的引用上,还有其他情况在极小概率下可能导致该现象,如果遇到,请加入依赖关系标签来告诉编译器正确的加载方式。