48

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?

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
user2018232
  • 503
  • 1
  • 4
  • 4
  • did you get an error message? – ianbarker Jan 28 '13 at 15:43
  • the function is undefined. – user2018232 Jan 28 '13 at 15:45
  • also "undefined is not a function " – user2018232 Jan 28 '13 at 15:50
  • 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 Jan 28 '13 at 16:31
  • Is the function foo() defined in test.js? I just tried the scenario you described and the call to foo() works perfectly. – richb01 Mar 09 '14 at 01:49
  • Here is a jsfiddle for an example: http://jsfiddle.net/richbuff/ALJwy/ – richb01 Mar 09 '14 at 02:00
  • 1
    Actually, in most cases the callback does fire after the script is executed - see [this question](http://stackoverflow.com/questions/21196617/jquery-getscript-load-vs-execution) and the [issue raised on jQuery's GitHub](https://github.com/jquery/api.jquery.com/issues/420). You need to figure out what's unique about your situation. Also @richb01, your site is down. – Dan Dascalescu Mar 29 '15 at 06:25
  • @user2018232 & @Bergi : wrap `getScript` inside jquery's `when` as mentioned here https://stackoverflow.com/a/32802388/1668797, it works!!! – sarathprasath Jan 17 '18 at 15:04

8 Answers8

16

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);
});
Community
  • 1
  • 1
Samuel Bergström
  • 1,869
  • 1
  • 12
  • 8
  • 4
    The issue is that success, .then, and .done, etc, are all called when the HTTP call completes, not when the fetched script is available to be executed. The problem with async issues is that they work for some people and not others, so you the results are dominated by "works for me, clearly you just don't understand promises" answers, which is what we have here. Well, this didn't work for me. :) – tekHedd Jun 19 '19 at 22:26
7

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

Aakash
  • 21,375
  • 7
  • 100
  • 81
  • 3
    I would say this is the best solution possible while I don't like dealing with `setInterval(...)` in my script. – eQ19 May 21 '18 at 09:39
3

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

DadViegas
  • 2,263
  • 16
  • 12
  • 3
    It still indicate that the prerequisite function in the script is not executed yet :( – user2018232 Jan 28 '13 at 16:04
  • 1
    I use this code and works for me, i had the same problem that you have. but was because get script has a callback function that is executed if the request succeeds, but the code is not available yet. – DadViegas Jan 28 '13 at 16:12
  • 1
    Thanks a lot anyway, I also saw this on documentation "As of jQuery 1.8, the use of async: false with jqXHR ($.Deferred) is deprecated; you must use the success/error/complete callback options instead of the corresponding methods of the jqXHR object such as jqXHR.done() or the deprecated jqXHR.success()." Not sure if it is related. – user2018232 Jan 28 '13 at 16:17
  • Does not solve the problem. It makes the HTTP call async, but the script is still not loaded inside success/.then. – tekHedd Jun 19 '19 at 22:28
3
$.getScript( "ajaxFile/myjs.js" )
.done(function( s, Status ) {
    console.warn( Status );
})
.fail(function( jqxhr, settings, exception ) {
    console.warn( "Something went wrong"+exception );
});
cweston
  • 11,297
  • 19
  • 82
  • 107
amee9451
  • 109
  • 7
  • 10
    Please try and explain your code a little. Stack Overflow is not a site to get "just the solution", the purpose is also to build knowledge. That's why code-only answers rarely deserve upvotes in my opinion. – 0x5C91 Jul 06 '14 at 10:22
  • Callback methods are deprecated in jQuery, Deferred handlers are the tested and supported method for attaching behavior to async loads. That said, I'm not sure they guarantee that the script will be executed by the time they're called. – Dtipson Apr 28 '16 at 13:11
3

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

} );
GDY
  • 2,872
  • 1
  • 24
  • 44
2

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.

BrunoRB
  • 889
  • 8
  • 14
0

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

Corey Alix
  • 2,694
  • 2
  • 27
  • 38
-1

$getScript use like this

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

this is working fine for me

Kathir
  • 4,359
  • 3
  • 17
  • 29
  • 7
    Please try and explain your code a little. Stack Overflow is not a site to get "just the solution", the purpose is also to build knowledge. – Dan Dascalescu Mar 29 '15 at 06:23
  • 1
    I think you've missed the point. The callback needs to use something defined in the script you just loaded. – Corey Alix Jul 13 '16 at 13:26