咦? Angular $ injector:nomod错误... async / defer脚本标签有趣,$ .readyWait / $ .poldReady似乎已损坏

时间:2017-04-06 05:33:43

标签: jquery angularjs document-ready labjs

=== TL; DR ===

  

简短版本(相信我,我整天都在研究这个问题):

     

我有一个很大的脚本列表,包括角度和非角度   东西(1.2.x)。当我尝试使用LAB.js加载它时,包括   AlwaysPreserveOrder标志,Angular太火了。挖掘,它   似乎Angular正在使用$(document).ready(/ * start angular * /)。   可理解的,脚本加载器破坏了正常的文档   事件

     

所以,我尝试使用$ .holdReady(true)和$ .holdReady(false),但是,我得到了   真奇怪的行为:虽然$ .holdReady(true)确实增加了   $ .readyWait按预期,它只是不会阻止角度   初始化......最重要的是,如果我尝试设置自己的监听器   对于$(document).ready(),它永远不会触发,即使有角度   似乎正在利用同样的事件开火...

     

...为了增添神秘色彩,每一次在蓝色的月亮中,如果我把它设置为   继续执行window.location.reload()失败,直到工作完成为止   实际上只会工作 - 很少。这使它看起来像一场比赛   条件,但鉴于我传递了订单标志,我不能   想象什么会比赛,这个线索似乎也不适合   其他一切,据我所知......

     

请注意,如果我切换到该文件的非lab.js版本,那就是一切   似乎工作得很好,包括$ .readyWait计数,一切   (包括角度)等待$ .holdReady(false)被调用,   $(document).ready()我自己解雇的标志等等。

====== LONG VERSION ======

我试图制作一个最不可行的例子,但现实世界的工作代码更加复杂available here,而破坏的版本是available here - 他们是仍然清理尽可能使问题尽可能明显,而不会消除任何潜在的混淆因素。

这有效:

<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>

第三个(上一个)是我真正想要的。

他们生成this error

  

模块&#39; mapmycustomersApp&#39;不可用!你要么拼错了   模块名称或忘记加载它。如果注册模块,请确保   您将依赖项指定为第二个参数。

在写这个答案时,我取得了一些进展,但遇到了一个新的死胡同,我发誓感觉就像是jquery或angular中的一个bug。

为什么呢?我可以跟踪它的最后面的部分告诉我,即使应用程序注册自己之前,angularInit()的调用太快了...... 在角度文件的底部调用,在第2232行:

  jqLite(document).ready(function() {
    angularInit(document, bootstrap);
  });

jqLit​​e设置为jQuery(我通过检查angular.element === $确认了这一点,这是真的,这在角度代码的其他地方得到证明)。 所以这应该只是在$(document).ready()上触发。 哪个已知加载器问题。 这就是他们创建$ .holdReady()的原因。

但出于某种原因,这对我不起作用。 我得到非常奇怪的输出。

这就是我的意思: 如果我将jquery脚本标记(2.2.4)移动到头顶部,然后在其下方调用$.holdReady(true),我可以看到$.readyWait递增。 (我甚至可以称它为好几次,并观察它最多四次。)

然后我在.wait(() => $.readyWait(false))次调用结束时粘贴了.script() ...但如果我在此之前安装了console.log,我可以看到它从中删除,比方说,已经40,意味着准备已经解雇了。 $.readyWait()什么也没做。

有价值的线索

很少,非工作代码有效......然后在刷新时再次失败,没有任何变化。这似乎表明了竞争条件,但我无法理解那将是什么,而且我不会与我所见过的其他情况对齐......然而,它发生了。 在这些时候,$ .readyWait返回1而不是0

我知道这很多,但我觉得这里完全不知所措。世界上到底发生了什么?

哦,还有一个让我感到困惑的非常重要的线索:$(document).ready(_ => console.log("I loaded"))永远不会运行。 $(window).load,否则相同,运行正常。在我宣布那个听众的地方并不重要,它永远不会为我开火,即使我把听众置于页面的顶部......然而它显然会以某种方式触发,因为它触发了什么{ {1}}!我的理解是,如果我打电话就应该开火,即使它已经被解雇了!

...只是为了表明我没有犯下一些非常明显的错误,所有相同的代码都会按预期触发(angularInit事件,而document ready两者都完全符合您的要求#&# 39; d expect)每当我切换到所有脚本标签时。

在代码中:

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

所有代码都是有用的,我只是想把所有代码都移到LAB.js上,发现自己无法做到。其他评论:切换到角度1.6.4只是为了好玩没有效果(除了完全没有加载完成那些罕见的成功,因为$ http()。成功不是一个函数,所以他们必须在更高版本中更改该API) ,我们在版本2中使用最新版本的jquery,切换到3+会引发其他不兼容错误。

1 个答案:

答案 0 :(得分:0)

我在确定问题时是正确的。在与Kyle Simpson的长时间讨论中,他指出在角度1.2x源代码中使用$.ready是基于错误假设的常见错误,这使得加载javascript源异步不可行。

出于某种原因,使用$.holdReady()最终确实有效。我不确定为什么它没有,但我怀疑我不小心包括了两次jquery依赖,覆盖了之前的readyCount。