开发者

Do I need to use window.onReady() after embedding a script asynchronously?

开发者 https://www.devze.com 2023-02-25 20:03 出处:网络
I\'m implementing functionality that loads a script asynchronously. After the XHR has completed, I insert the code into the document and call a ca开发者_运维百科llback method. The callback method uses

I'm implementing functionality that loads a script asynchronously. After the XHR has completed, I insert the code into the document and call a ca开发者_运维百科llback method. The callback method uses that dynamically loaded code.

What I am wondering is that does my callback get called before the appended script is parsed? Do I need to use window.onReady() and let the browser engine parse the appended script and fire window.onReady() and just then call my callback method?

Please do not tell me to use <your favority library here>, because I am doing this to learn.

Edit: Or, should I insert a script element with the src and async set, and listen to the script element's readystatechange event?


It really depends on how you are loading it.

You could load a script, and then just eval() the responseText after you have loaded it.

Or, you could also document.createElement('script'), and then call the callback method.

Pusuedocode:

load_xhr('path/to/js', function onReady (responseText) {

eval(responseText);

//OR

var script = document.createElement('script');

script.text = responseText;

//Append element to DOM

//THEN

callback_method();

});

Edit: Or, should I insert a script element with the src and async set, and listen to the script element's readystatechange event?

If you do that, the browser's loading symbol will show. If you load it via XHR, the user won't notice anything.


It depends an what you want to do in your script

Here is an example of injecting in a script before the dom is ready and it calling a callback function.

var callback = function() { console.log('hi you called'); };

document.write('<script type="text/javascript" charset="utf-8">// code\n callback();<\/script>');

If the script needs to work with the dom then it needs to wait until it's ready otherwise not.

However your solution will need to be tested in all the browsers you wish to support, as the order of script evaluation and execution differs in for example IE and FF.


Or, should I insert a script element with the src and async set, and listen to the script element's readystatechange event

The most reliable way is to insert a script element with src set (don't set async or defer, no need). For notification that the script has been loaded and parsed, do one of two things:

  1. Have the script tell you when it's ready. E.g., have it call a function that you already have defined on your page. This is the best thing to do if you control the script you're loading.

    Example (live copy):

    The script:

    function foo() {
        display("foo() called");
    }
    callWhenReady();
    

    The script loading it:

    var script;
    display("Loading script " + url + "...");
    script = document.createElement('script');
    script.src = url;
    document.body.appendChild(script);
    
    function callWhenReady() {
      display("Script says it's ready, calling foo...");
      foo();
    }
    
  2. Use a self-rescheduling setTimeout loop to look for a symbol the script defines (presumably you know one, you want to call into it). Or you could use setInterval, but that requires you keep track of the timer handle and frankly I prefer the control that a self-rescheduling setTimeout gives me.

    Example (live copy):

    The script (note no callback):

    function foo() {
        display("foo() called");
    }
    

    The loading script:

    var script;
    display("Loading script " + url + "...");
    script = document.createElement('script');
    script.src = url;
    document.body.appendChild(script);
    watchFor('foo');
    
    function watchFor(fname) {
      if (typeof foo === "function") {
        display("foo detected! Calling...");
        foo();
      }
      else {
        // Not found yet, wait
        setTimeout(function() {
          watchFor(fname);
        }, 50);
      }
    }
    
  3. Update: Re your comment below: If you really know nothing about the script being loaded, and you can't have the script call you, it's unclear to me why you need to receive the event. (What will you do, if you don't know any of its global symbols and so can't call any functions it adds?) But most browsers support the load event on script elements, and for those that don't (earlier IEs, mostly), there's the readystatechange event. For this situation, you could use a combination of those:

    Example (live copy):

    var script;
    display("Loading script " + url + "...");
    script = document.createElement('script');
    script.onload = function() {
      display("Script loaded (notification via load event). Calling foo just to prove it's loaded, but in the question we wouldn't know about the symbol do we wouldn't be able to call it.");
      foo();
    };
    script.onreadystatechange = function() {
      if (script.readyState === "loaded") {
        display("Script loaded (notificaton via readyState). Calling foo just to prove it's loaded, but in the question we wouldn't know about the symbol do we wouldn't be able to call it.");
        foo();
      }
    };
    document.body.appendChild(script);
    script.src = url;
    

    That works via the load event on Chrome 10, Firefox 3.6, Safari 5, and Mobile Safari; via the readystatechange event in IE6, IE7, and IE8; and via both events in Opera 11 and IE9.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号