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:
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(); }
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 usesetInterval
, but that requires you keep track of the timer handle and frankly I prefer the control that a self-reschedulingsetTimeout
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); } }
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 onscript
elements, and for those that don't (earlier IEs, mostly), there's thereadystatechange
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 thereadystatechange
event in IE6, IE7, and IE8; and via both events in Opera 11 and IE9.
精彩评论