同步加载和执行javascript代码

时间:2011-05-20 16:19:28

标签: javascript load synchronous

有没有办法像同步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

6 个答案:

答案 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框结束。你的情况也是如此。第一批代码必须在其他任何东西开始之前完成执行。

为什么你得到例外(在例子2中)

在我写完答案后你添加了一些代码,所以这里有更多的信息。

添加脚本标记不会立即执行它。当HTML解析器到达您添加的SCRIPT元素时,将发生脚本加载+执行。它将在该点加载它并评估/执行其内容。

  1. HTML解析器开始解析您的文档
  2. 正在解析
  3. HEAD并解析并执行其SCRIPT子标记。此执行会向尚未解析的BODY标记添加一个元素。
  4. Parser转到BODY并解析其内容(新添加的SCRIPT标记),然后加载脚本并执行其内容。
  5. 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();
}