=== TL;DR ===
简短版(相信我,我整天都在研究这个):
我有一大堆脚本,包括有角和无角的东西(1.2.x)。当我尝试使用 LAB.js 加载所有内容时,包括 AlwaysPreserveOrder 标志,Angular 过早触发。深入研究,Angular 似乎正在使用 $(document).ready(/* start angular */)。可以理解,脚本加载器会破坏正常的 document.ready 事件。
所以,我尝试使用 $.holdReady(true) 和 $.holdReady(false),但是,我得到了非常奇怪的行为:虽然 $.holdReady(true) 确实按预期增加了 $.readyWait,但它不会阻止 angular从初始化......最重要的是,如果我尝试为 $(document).ready() 设置我自己的侦听器,它永远不会触发,即使 angular 似乎使用相同的事件来触发......
...为了增加谜团,每一次在一个蓝月亮,如果我将它设置为在失败时继续执行 window.location.reload() 直到一切正常,它实际上会正常工作 - 很少。这使它看起来像是一种比赛条件,但鉴于我正在传递订单标志,我无法想象会发生什么比赛,据我所知,这条线索似乎也不适合其他一切...... .
请注意,如果我切换到文件的非 lab.js 版本,一切似乎都工作得很好,包括 $.readyWait 计数,所有(包括角度)等待 $.holdReady(false) 被调用,$(document)我自己开火的 .ready() 标志等。
======长版======
我正在尝试制作一个最小的可行示例,但这里提供了更复杂的现实世界工作代码,这里提供了一个损坏的版本——它们仍在清理以尝试使问题尽可能明显,而不消除任何潜在的混杂因素。
这有效:
<body ng-app="mapmycustomersApp" ng-strict-di>
<script src="build/libraries/LAB.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.32/angular.min.js"></script>
<script src="https://code.angularjs.org/1.2.32/angular-resource.min.js"></script>
<script src="https://code.angularjs.org/1.2.32/angular-route.min.js"></script>
<script>
document.write('<script src="build/app.js"></script>')
document.write('<script src="build/controllers/main.js"></script>')
</script>
</body>
这不会:
<body ng-app="mapmycustomersApp" ng-strict-di>
<script src="build/libraries/LAB.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.32/angular.min.js"></script>
<script src="https://code.angularjs.org/1.2.32/angular-resource.min.js"></script>
<script src="https://code.angularjs.org/1.2.32/angular-route.min.js"></script>
<script>
$LAB.setGlobalDefaults({ AlwaysPreserveOrder: true });
$LAB
.script("build/app.js")
.script("build/controllers/main.js")
</script>
</body>
这也不是:
<body ng-app="mapmycustomersApp" ng-strict-di>
<script src="build/libraries/LAB.min.js"></script>
<script>
$LAB.setGlobalDefaults({ AlwaysPreserveOrder: true });
$LAB
.script("https://ajax.googleapis.com/ajax/libs/angularjs/1.2.32/angular.min.js")
.script("https://code.angularjs.org/1.2.32/angular-resource.min.js")
.script("https://code.angularjs.org/1.2.32/angular-route.min.js")
.script("build/app.js")
.script("build/controllers/main.js")
</script>
</body>
第三个(上面的最后一个)是我真正想要的。
他们产生这个错误:
模块“mapmycustomersApp”不可用!您要么拼错了模块名称,要么忘记加载它。如果注册模块,请确保将依赖项指定为第二个参数。
在写这个答案时,我取得了一些进展,但遇到了一个新的死胡同,我发誓感觉就像 jquery 或 angular 中的错误。
为什么?我可以追溯到最远的地方告诉我 angularInit() 被调用得太早了,早在应用程序注册之前......这在 angular 文件的底部被调用,在第 2232 行:
jqLite(document).ready(function() {
angularInit(document, bootstrap);
});
jqLite 设置为 jQuery(我通过检查 angular.element === $ 确认了这一点,这是真的,这在 Angular 代码的其他地方得到了证明)。所以这应该只是在 $(document).ready() 上触发。装载机的已知问题。这就是他们创建 $.holdReady() 的原因。
但由于某种原因,这对我不起作用。 我得到非常奇怪的输出。
这就是我的意思:如果我将一个 jquery 脚本标签 (2.2.4) 移动到头顶,然后$.holdReady(true)
在它的正下方调用,我可以看到它$.readyWait
是递增的。(我什至可以多次调用它,然后看着它上升到四次。)
然后我.wait(() => $.readyWait(false))
在我的通话结束时加上a .script()
...但是如果我在那之前 console.log ,我可以看到它已经从,比如说,已经下降了4
,0
这意味着 ready 已经被解雇了。$.readyWait()
什么都没做。
有价值的线索:
很少,非工作代码工作......然后在刷新时再次失败,没有任何变化。这似乎表明了一种竞争条件,但我不明白那会在哪里,而且这与我见过的其他情况不符……然而,它发生了。在那些时候, $.readyWait 返回 1 而不是 0。
我知道这很多,但我在这里感到完全困惑。世界上到底发生了什么?
哦,还有一个令我困惑的非常重要的线索:$(document).ready(_ => console.log("I loaded"))
永远不会跑。$(window).load
,否则相同,运行良好。不管我在哪里声明那个监听器,它永远不会为我触发,即使我将监听器设置在页面的顶部......但它显然会以某种方式触发,因为它是触发的angularInit
!我的理解是,如果我调用它,它应该会触发,即使它已经触发了!
...只是为了表明我没有犯一些非常明显的错误,只要我切换到所有脚本标签,所有相同的代码都会按预期触发(document ready
事件和holdReady()
两者都完全按照您的预期进行)。
在代码中:
<!doctype html>
<html>
<head>
<script src="https://code.jquery.com/jquery-2.2.4.js"></script>
<script>
$(window).load(function() {
console.log("this fires");
});
$(document).ready(function() {
console.log("this doesn't");
debugger;
});
console.log("holding ready", $.readyWait);
$.holdReady(true);$.holdReady(true);$.holdReady(true); // needed because we use LAB.js, which messes with Document.ready, which Angular depends on
console.log('rw, ', $.readyWait)
</script>
(详情:
app.js
包括
var app = angular.module('mapmycustomersApp' ['ngRoute','ui.bootstrap','ngStorage','ngFileUpload'])
.config(['$routeProvider', '$locationProvider', '$compileProvider', function($routeProvider, $locationProvider, $compileProvider) { // ...
并main.js
包括
app.controller('MainCtrl', ['$scope', '$http', // ...
所有代码都可以正常工作,我只是想把所有东西都移到 LAB.js 上,却发现自己做不到。其他评论:仅仅为了好玩而切换到 Angular 1.6.4 没有效果(除了因为 $http().success 不是一个函数,所以他们必须在以后的版本中更改了那个 API) ,并且我们在版本 2 中使用最新版本的 jquery,切换到 3+ 会引发其他不兼容错误。