Load and execute javascript code SYNCHRONOUSLY
Is there a way to load and execute a javascript file in a synchronous way just like a synchronous XMLHttpRequest?
I'm currently using a sync XMLHttpRequest and then eval for this, but debugging that code is very difficult...
Thanks for your help!
Update
I tried this now:
test.html
<html&开发者_如何学运维gt;
<head>
<script type="text/javascript">
var s = document.createElement("script");
s.setAttribute("src","script.js");
document.head.appendChild(s);
console.log("done");
</script>
</head>
<body>
</body>
</html>
script.js
console.log("Hi");
Output: done Hi
So it was not executed synchronously. Any idea to make "Hi" appear first?
Update 2 Other example
test.html (code inside a script tag)
var s = document.createElement("script");
s.setAttribute("src","script.js");
document.head.appendChild(s);
SayHi();
script.js
function SayHi(){
console.log("hi");
}
Output: Uncaught ReferenceError: SayHi is not defined
If you use this:
function loadScriptSync (src) {
var s = document.createElement('script');
s.src = src;
s.type = "text/javascript";
s.async = false; // <-- this is important
document.getElementsByTagName('head')[0].appendChild(s);
}
You can do what you want (although divided up in an additional script file)
test.html (code inside a script tag):
loadScriptSync("script.js");
loadScriptSync("sayhi.js"); // you have to put the invocation into another script file
script.js:
function SayHi() {
console.log("hi");
}
sayhi.js:
SayHi();
All scripts which are loaded after DOM is ready are loaded asynchronously. The only reason for browser to load them synchronously is function write
which can output something. So you can use onload callback of the script element to achieve what you want.
var s = document.createElement("script");
s.setAttribute("src","script.js");
s.onload = function(){
console.log('Done');
}
document.head.appendChild(s);
Another way is to load js-file via XHR and set code inside the script element:
window.onload = function(){
var req = new XMLHttpRequest();
req.open('GET', "test.js", false);
req.onreadystatechange = function(){
if (req.readyState == 4) {
var s = document.createElement("script");
s.appendChild(document.createTextNode(req.responseText));
document.head.appendChild(s);
}
};
req.send(null);
}
From a similar question ( https://stackoverflow.com/a/3292763/235179 ):
<script type="text/javascript">
document.write('<script type="text/javascript" src="other.js"><\/script>');
</script>
<script type="text/javascript">
functionFromOther();
</script>
Either the code called from the document.write
'd script needs to be in it's own <script>
or it needs to be in the window.onload()
event.
Your scripts do execute synchronously
your code if put together is:
1. create script element
2. set its attribute src
3. set its attribute deferred
4. display done...
this first part stops execution and hands it over to next script
5. script executes and displays Hi
Everything is very much synchronous... In Javascript some code is executed completely until it executes to the last line or hands execution over to internal systems (like XHR or timer).
When one would like to put prepare some parts to execute later on, they prepare it with setTimeout
. Even if timeout is shorter than the rest of the code will take that's the time it will execute. After code has finished executing. Example:
// some code
setTimeout(function(){ alert("I'm second alert"); }, 1);
longExecutionTask();
alert("I'm the first alert");
In the above code even if setTimeout
is set to execute after 1ms it won't start until the code after it finishes execution which ends with displaying an alert
box. The same happens in your case. The first batch of code has to finish executing before anything else can start.
Why you're getting exception (in example 2)
You've added some more code after I've written my answer so here goes some more info.
Adding a script tag will not immediately execute it. Script loading+execution will happen when HTML parser will get to the SCRIPT
element you added. It will load it at that point and evaluate/execute its content.
- HTML parser starts parsing your document
HEAD
is being parsed and itsSCRIPT
child tag gets parsed and executed. This execution adds one more element toBODY
tag that hasn't been parsed yet.- Parser moves on to
BODY
and parses its content (the newly addedSCRIPT
tag) which then loads the script and executes its content.
SCRIPT
elements get immediately executed only when you they're added after your page has been parsed and is already rendered in browser. In your case that is not the case. The first script executes immediately and the dynamically added one executes when parses gets to it.
You can synchronize asynchronous operations among themself. Create recursive function to represent a loop and call the next operation when previous finish. The following function imports scripts in order with the similar technique. It waits a script to be loaded and if there is no error continues with the next. If an error occur it calls the callback function with the error event and if there is no error - calls the same callback function with null after all scripts are loaded. It also cleans after itself with s.parentNode.removeChild(s)
.
function importScripts(scripts, callback) {
if (scripts.length === 0) {
if (callback !== undefined) {
callback(null);
}
return;
}
var i = 0, s, r, e, l;
e = function(event) {
s.parentNode.removeChild(s);
if (callback !== undefined) {
callback(event);
}
};
l = function() {
s.parentNode.removeChild(s);
i++;
if (i < scripts.length) {
r();
return;
}
if (callback !== undefined) {
callback(null);
}
};
r = function() {
s = document.createElement("script");
s.src = scripts[i];
s.onerror = e;
s.onload = l;
document.head.appendChild(s);
};
r();
}
You can use the "defer" attribute when including the js file.
<script defer="defer" src="contact/js/frontend/form.js"></script>
精彩评论