【问题标题】:Infinite loop on window.init() in GAE/Angular appGAE/Angular 应用程序中 window.init() 的无限循环
【发布时间】:2015-04-28 06:03:30
【问题描述】:

我正在使用带有 AngularJS 的 cloud enpoints 演示,并且在加载 client.js 后,我使用他们建议的运行授权的方法遇到了无限循环。这是建议的方法。

首先,在所有其他脚本标签之后(对于 Angular 和其他 JS 文件,我正在这样做):

<script>
    function init() {
        window.init();
    }
</script>
<script src="https://apis.google.com/js/client.js?onload=init"></script>

然后,在控制器中,我像这样处理窗口初始化:

    $window.init = function () {
        // Loads the OAuth and helloworld APIs asynchronously, and triggers login
        // when they have completed.
        var apisToLoad;
        var callback = function () {
            if (--apisToLoad == 0) {
                googleAPI.signin(true,
                    googleAPI.userAuthed);
                appContext.appReady = true;
                alert('loaded');
            }
        }

        apisToLoad = 2; // must match number of calls to gapi.client.load()
        gapi.client.load('helloworld', 'v1', callback, googleAPI.apiRoot);
        gapi.client.load('oauth2', 'v2', callback);
    };

我认为我发现这里存在竞争条件,其中 $window.init 没有足够早地设置,所以我最终得到以下消息:

未捕获的 RangeError:超出最大调用堆栈大小

这是因为“window.init()”只是回调了init()函数,超出了栈。

关于如何更好地处理这个问题有什么建议吗?谢谢。

【问题讨论】:

    标签: javascript angularjs google-app-engine


    【解决方案1】:

    通过这样做,您是在告诉 window.init 调用自身,从而创建一个无限循环。

    <script>
        function init() {
            window.init();
        }
        init===window.init; // => true
    </script>
    <script src="https://apis.google.com/js/client.js?onload=init"></script>
    

    如果您更仔细地查看my code,您会发现我对函数的命名不同,如下所示:

    <script>
        function init() {
            window.initGapi();
        }
        init===window.initGapi; // => false
    </script>
    <script src="https://apis.google.com/js/client.js?onload=init"></script>
    

    然后在你的控制器中简单地定义initGapi

    $window.initGapi = function () {}
    

    接受答案的 cmets 中的代码等到加载 api 以引导应用程序,这需要更长的时间。

    【讨论】:

      【解决方案2】:

      把它放在“我错过了一些非常基本的东西”的箱子里:

      我注意到我在控制器定义中忘记了一些内容:

      topNavBar.$inject = ['$location', 'appContext', 'logger'];
      function topNavBar($location, $window, appContext, logger) {
      

      注意,注入中没有“$window”,因此它得到了 appContext 的定义,并且执行“$window.init =”完全没有效果。

      【讨论】:

      • 另外一个小笔记。这个方法,我第一次看到here,如果它在全局范围内效果更好(没有iffe)。
      • 呃!似乎这里仍然存在竞争条件。也许 10 次尝试中的 1 次,我收到堆栈超出消息。
      【解决方案3】:

      第一行在这里创建了一个无限循环,因为您在实际的 window.init 中调用了 window.init。

      <script>
          /**
           * Initializes the Google API JavaScript client. Bootstrap the angular module after loading the Google libraries
           * so that Google JavaScript library ready in the angular modules.
           */
          function init() {
              gapi.client.load('conference', 'v1', null, '//' + window.location.host + '/_ah/api');
              gapi.client.load('oauth2', 'v2', callback);
          };
      </script>
      <script src="//apis.google.com/js/client:plusone.js?onload=init"></script>
      

      你可以试试这个代码,看看是否对你更有意义

      【讨论】:

      • 是的,我可以看到它是如何工作的,但我们的想法是进入 Angular 控制器逻辑来处理身份验证,这将把它拉出来。我知道这可行,但我想将会话信息存储在 Angular 工厂中。
      • 看看这段代码:github.com/udacity/ud859/tree/master/ConferenceCentral_Complete/… 它可能会给你一个更好的处理方法。
      • 老兄,你摇滚!做到了。
      【解决方案4】:

      看起来你的角度控制器没有及时加载/执行,不知道为什么,但你可以等待文档准备好,以真正的 jQuery 方式:

      function init() {
          angular.element(document).ready(function() {
              window.init();
          });
      }
      

      到那时 Angular 应该已经完成​​加载了。

      【讨论】:

      • 实际上没有帮助。刚刚进入另一个无限循环,因为我认为 window.init() 仍然导致“就绪”再次捕获。
      • 您确定您的角度代码正在正确加载和执行?更改控制器中的函数名称,看看会发生什么,它要么工作要么抛出 undefined。
      • 如果我只是将我的函数重命名为“init1”,什么都不会发生,只是不会被调用。但是,如果我也将 onload 分配重命名为“init1”,那么我会在“window.init();”上得到未定义称呼。在我看来,“$window.init = function()”分配并没有真正分配。最后,我注意到我做错了什么。请参阅下面的答案。
      • 这不是一个解决方案,真的!
      猜你喜欢
      • 1970-01-01
      • 2019-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-29
      • 2015-11-10
      • 1970-01-01
      相关资源
      最近更新 更多