开发者问题收集

GAE/Angular 应用程序中的 window.init() 无限循环

2015-02-26
761

我正在使用带有 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 没有足够早地设置,所以我最终收到以下消息:

Uncaught RangeError: Maximum call stack size exceeded

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

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

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>

您可以尝试此代码以查看是否对您更有意义

Albertoimpl
2015-02-26

看起来您的角度控制器没有及时加载/执行,无法找出原因,但您可以等待文档准备好,以真正的 jQuery 方式:

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

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

Jaime Gomez
2015-02-26

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

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

如果您仔细查看 我的代码 ,您会发现我以不同的方式命名了这些函数,如下所示:

<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 () {}

对已接受答案的注释中的代码会等到 api 加载后才启动应用程序,这需要更长的时间。

willlma
2015-06-03