Infinite loop on window.init() in GAE/Angular app

2019-08-09 17:45发布

I'm using the cloud enpoints demo with AngularJS and I'm running into an infinite loop with their suggested method of running the authorization after the client.js is loaded. Here is the suggested method.

First, after all other script tags (for Angular and other JS files, I'm doing this):

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

Then, in a controller, I handle the window init like:

    $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);
    };

What I think I'm finding is that there is a race condition here where the $window.init is not set up early enough so I end up with the message:

Uncaught RangeError: Maximum call stack size exceeded

This is due to the fact that the "window.init()" just calls back to the init() function and exceeds the stack.

Any suggestions on how I can better handle this? Thanks.

4条回答
疯言疯语
2楼-- · 2019-08-09 18:17

Put this in the "I missed something really basic" bin:

I noticed that I forgot something in my controller definition:

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

Notice, no '$window' in the inject, so it got the definition for appContext and doing a "$window.init = " had absolutely no effect.

查看更多
再贱就再见
3楼-- · 2019-08-09 18:23

By doing this, you're telling window.init to call itself, creating an infinite loop.

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

If you look at my code more closely, you'll see that I name the functions differently, like so:

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

Then simply define initGapi in your controller instead:

$window.initGapi = function () {}

The code in the comments to the accepted answer waits until the api is loaded to bootstrap the app, which takes longer.

查看更多
Animai°情兽
4楼-- · 2019-08-09 18:32

Looks like your angular controllers are not loading/executing in time, can't tell why but you could wait for document ready, in true jQuery fashion:

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

Angular should've finished loading by then.

查看更多
smile是对你的礼貌
5楼-- · 2019-08-09 18:36

The first line is creating an infinite loop there because you are calling window.init inside the actual 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>

You can try this code to see if makes more sense for you

查看更多
登录 后发表回答