46
votes

As from the jquery api page http://api.jquery.com/jQuery.getScript/

Success Callback

The callback is fired once the script has been loaded but not necessarily executed.

$.getScript("test.js", function() {
    foo();
});

if the foo() function depend on test.js, it cannot be execute successfully.

I saw similar thing with google map api but in that case you can specify the callback function in the ajax script url. But in general is there an obvious way to wait until the ajax script executed to do the callback?

8
did you get an error message?ianbarker
the function is undefined.user2018232
also "undefined is not a function "user2018232
if you're using chrome or firefox; does it echo to the console if you put console.log('xxxx'); into the callback function rather than foo();ianbarker
Actually, in most cases the callback does fire after the script is executed - see this question and the issue raised on jQuery's GitHub. You need to figure out what's unique about your situation. Also @richb01, your site is down.Dan Dascalescu

8 Answers

15
votes

I know it is an old question but i think both answers containing "done" are not explained by their owners and they are in fact the best answers.

The most up-voted answer calls for using "async:false" which will in turn create a sync call which is not optimal. on the other hand promises and promise handlers were introduced to jquery since version 1.5 (maybe earlier?) in this case we are trying to load a script asynchronously and wait for it to finish running.

The callback by definition getScript documentation

The callback is fired once the script has been loaded but not necessarily executed.

what you need to look for instead is how promises act. In this case as you are looking for a script to load asynchronously you can use either "then" or "done" have a look at this thread which explains the difference nicely.

Basically done will be called only when a promise is resolved. in our case when the script was loaded successfully and finished running. So basically in your code it would mean:

$.getScript("test.js", function() {
    foo();
});

should be changed to:

$.getScript("test.js").done(function(script, textStatus) {
    console.log("finished loading and running test.js. with a status of" + textStatus);
});
5
votes

$.getScript(...) + setInterval(...) worked for me:

$.getScript('https://www.google.com/recaptcha/api.js')
  .done(function() {
    var setIntervalID = setInterval(function() {
      if (window.grecaptcha) {
        clearInterval(setIntervalID);
        console.log(window.grecaptcha);
        letsWorkWithWindowDotGreptcha();
      };
    }, 300);
  });


  function letsWorkWithWindowDotGreptcha() {
    // window.greptcha is available here....
  }

Once the variable we are looking for is defined (in my case window.grecaptcha, i can call a closure function which can be abstracted out.

Good Luck...

3
votes

You can use ajax

jQuery.ajax({
        async:false,
        type:'GET',
        url:script,
        data:null,
        success:callback,
        dataType:'script'
    });

Async is false, because you want to load and execute the script, after that in success callback you can call your function foo()

3
votes
$.getScript( "ajaxFile/myjs.js" )
.done(function( s, Status ) {
    console.warn( Status );
})
.fail(function( jqxhr, settings, exception ) {
    console.warn( "Something went wrong"+exception );
});
2
votes

I was facing the same issue today and came up with a solution based on promises and a interval timer:

$.getScript("test.js", function() {
    var $def = $.Deferred();
    if (typeof foo === 'undefined') { // "foo" isn't available
        var attempts = 0;
        // create an interval
        // that will check each 100ms if the "foo" function
        // was loaded
        var interval = setInterval(function() {
            if (typeof foo !== 'undefined') { // loaded
                window.clearInterval(interval);
                $def.resolve();
            }
            // after X unsuccessfull attempts, abort the operation
            else if (attempts >= 100) {
                window.clearInterval(interval);
                $def.reject('Something went wrong');
            }

            attempts++;
        }, 100);
    }
    else { // "foo" is available
        $def.resolve();
    }
    return $def.promise();
}).then(function() {
    // at this point "foo()" is definitely available.
}).fail(function() {
    // deal with the failure
});

The ideia is that you load a given script that will expose some variable (the foo function in your question example) that still doesn't exist, so after the script is loaded by getScript you check if this variable exists, if not you create an interval that will continuously check if the variable is available, and only when this condition is satisfied you resolve the promise.

1
votes

As mentioned then, done and the $.getScript callback fire when the script was loaded and not executed wich may be to early … intervals may be a way of tackling this but in my opinion it seems not very elegant.

My solution is triggering an event inside the async loaded script like:

jQuery( document ).trigger( 'loadedeventsjs' );

And inside my main script i could bind to that event like:

jQuery( document ).on( 'loadedeventsjs', function() {

    jQuery( '#mainmenu_wrapper' ).on( 'swiperight', menuout );

} );
0
votes

I'm afraid the solution requires polling for the dependency. Alternatively the script needs to be wrapped in a pre-defined callback like AMD.

-1
votes

$getScript use like this

$.getScript( "js/jquery.raty.min.js" )
    .done(function( script, textStatus ) {
          console.log( textStatus );
         }
          });

this is working fine for me