有没有办法像同步XMLHttpRequest一样以同步方式加载和执行javascript文件?
我目前正在使用同步XMLHttpRequest,然后使用eval,但调试该代码非常困难......
感谢您的帮助!
更新
我现在尝试了这个:
的test.html
<html>
<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");
输出: DONE 喜
所以它没有同步执行。任何让“嗨”出现的想法都会先出现?
更新2 其他例子
test.html(脚本标记内的代码)
var s = document.createElement("script");
s.setAttribute("src","script.js");
document.head.appendChild(s);
SayHi();
的script.js
function SayHi(){
console.log("hi");
}
输出:未捕获的ReferenceError:未定义SayHi
答案 0 :(得分:20)
如果您使用此:
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);
}
您可以执行您想要的操作(尽管在其他脚本文件中划分)
test.html (脚本代码中的代码):
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();
答案 1 :(得分:16)
在DOM准备就绪后加载的所有脚本都是异步加载的。浏览器同步加载它们的唯一原因是函数write
可以输出一些东西。所以你可以使用脚本元素的onload回调来实现你想要的。
var s = document.createElement("script");
s.setAttribute("src","script.js");
s.onload = function(){
console.log('Done');
}
document.head.appendChild(s);
另一种方法是通过XHR加载js文件并在脚本元素中设置代码:
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);
}
答案 2 :(得分:11)
来自类似的问题(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>
从document.write
'd脚本中调用的代码需要位于其自己的<script>
中,或者需要位于window.onload()
事件中。
答案 3 :(得分:5)
你的代码如果放在一起是:
1. create script element
2. set its attribute src
3. set its attribute deferred
4. display done...
第一部分停止执行并将其移交给下一个脚本
5. script executes and displays Hi
一切都是非常同步的...在Javascript中,一些代码被完全执行,直到它执行到最后一行或将执行交给内部系统(如XHR或计时器)。
如果想要准备一些部分以便稍后执行,他们会使用setTimeout
进行准备。即使超时比其余代码短,也会花费它执行的时间。代码完成执行后。例如:
// some code
setTimeout(function(){ alert("I'm second alert"); }, 1);
longExecutionTask();
alert("I'm the first alert");
在上面的代码中,即使setTimeout
设置为在1ms之后执行,它也不会在完成执行后的代码开始,直到显示alert
框结束。你的情况也是如此。第一批代码必须在其他任何东西开始之前完成执行。
在我写完答案后你添加了一些代码,所以这里有更多的信息。
添加脚本标记不会立即执行它。当HTML解析器到达您添加的SCRIPT
元素时,将发生脚本加载+执行。它将在该点加载它并评估/执行其内容。
HEAD
并解析并执行其SCRIPT
子标记。此执行会向尚未解析的BODY
标记添加一个元素。BODY
并解析其内容(新添加的SCRIPT
标记),然后加载脚本并执行其内容。 SCRIPT
个元素只有在您的页面被解析并且已经在浏览器中呈现后才会被添加。在你的情况下,情况并非如此。第一个脚本立即执行,动态添加的脚本在分析到达时执行。
答案 4 :(得分:1)
当包含js文件时,您可以使用“ defer”属性。
<script defer="defer" src="contact/js/frontend/form.js"></script>
答案 5 :(得分:0)
您可以在自己之间同步异步操作。创建递归函数以表示循环,并在上一次完成时调用下一个操作。以下函数使用类似的技术按顺序导入脚本。它等待加载脚本,如果没有错误继续下一个。如果发生错误,它会使用错误事件调用回调函数,如果没有错误,则在加载所有脚本后调用相同的回调函数。它还会使用s.parentNode.removeChild(s)
进行清理。
function importScripts(scripts, callback) {
if (scripts.length === 0) {
if (callback !== undefined) {
callback(null);
}
}
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();
}