2

我做了一个非常简单的例子(改编自我的真实项目),它使用 LABjs (v2.0.3) 加载 javascript 文件并以给定的顺序执行它们。我正在粘贴下面的代码。

  • 由于 testLAB.js 等待 mainCanvas.js,而 mainCanvas.js 等待 events.js,我希望警报的顺序是:“events.js”“mainCanvas.js”“testLAB.js”。
  • 但是,我通常得到相反的顺序:“testLAB.js”“mainCanvas.js”“events.js”。
  • 有时我会得到“testLAB.js”“events.js”“mainCanvas.js”。

谁能解释一下?
完整的例子可以在这里下载。

编辑:我正在使用 node.js 和http-server 模块在本地提供这些页面(以防您也想在本地尝试)

文件:index.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Test lab.js</title>
    <script src="js/lib/LAB.js"></script>
    <script src="js/app/testLAB.js"></script>
</head>
<body>
</body>
</html>

文件:js/app/testLAB.js

$LAB.setGlobalDefaults({
    BasePath: "/js/",
    Debug:true
});

$LAB
.script("lib/underscore.min.js")
.script("app/mainCanvas.js").wait(function(){
    alert("testLAB.js");
});

文件:js/app/mainCanvas.js

$LAB
.script("lib/jquery.js").wait()
.script("lib/underscore.min.js")
.script("app/events.js")
.wait(function() {
    alert("mainCanvas.js");
});

文件:js/app/events.js

$LAB
.script("lib/jquery.js")
.script("lib/underscore.min.js")
.wait(function() {
alert("events.js");
});
4

1 回答 1

3

这里的问题是对 LABjs 的工作原理的误解,或者更确切地说,是对嵌套动态脚本加载的工作原理的误解。

如果我使用脚本加载器加载脚本 A.js,浏览器将下载然后执行该脚本的内容,在脚本 A 中,我使用脚本加载器加载脚本 B.js,事实上脚本 A.js要求 B.js 加载并不意味着 A.js 的“加载”事件被神奇地阻止,直到依赖项(即在本例中为 B.js)完成加载和执行。

脚本加载后,浏览器会立即执行,一旦主要执行完成,浏览器将在该脚本上触发“加载”事件,表明它已完成。如果该脚本触发了其他一些异步行为,例如加载更多脚本,则该异步行为将不会影响主执行线程或触发该脚本的“加载”事件。

如果您需要加载嵌套依赖项,您将需要一个更复杂的系统来“延迟”每个文件的执行,类似于 AMD 加载器(如 Require.js)如何将所有代码包装在函数中。该技术起作用的原因是被声明的外部函数的执行顺序无关紧要,因为在定义了所有代码之后,您可以返回并以各种正确的顺序执行这些函数有效负载并获得您期望的顺序。


如果您不想走 AMD/Require 路线,另一个(更简单的?)选项是我个人所做的,是使用一个简单的构建工具脚本,在构建时读取您的 JS 文件,发现所有内容嵌套的依赖项是,并以正确的顺序将它们全部“提升”到一个“全局”$LAB 链调用中。因此,在您的文件中,不要使用实际的 $LAB 调用声明嵌套依赖项,而只需使用 JS 注释中的依赖关系表示法,然后让您的脚本查找这些依赖项。

示例(类似于我自己做事的方式):

A.js:

// needs "B.js"
// needs "C.js"

A.something = function( /*..*/ ) { /*..*/ };    
B.something();
C.something();

B.js:

// needs "D.js"

B.something = function( /*..*/ ) { /*..*/ };
D.something();

C.js:

// needs "D.js"
// needs "E.js"

C.something = function( /*..*/ ) { /*..*/ };
D.something();
E.something();

D.js:

D.something = function( /*..*/ ) { /*..*/ };

E.js:

E.something = function( /*..*/ ) { /*..*/ };

然后,我有一个简单的脚本来查看我的文件,并发现必要的执行顺序,以便满足所有依赖项。

然后它会生成一个 $LAB 链供我的主页使用,如下所示:

$LAB
.script("D.js")
.script("E.js").wait() // D and E can execute in either order
.script("B.js")
.script("C.js").wait() // B and C can execute in either order
.script("A.js")
.wait(function(){
   alert("Everything is loaded!");
});

像我建议的方法的唯一警告是你不能做循环依赖(比如 C 依赖于 B 和 B 依赖于 C)。如果您需要循环依赖,请转到 AMD/Require.js。

于 2013-04-12T17:20:52.180 回答