繁体   English   中英

同步加载和执行 javascript 代码

[英]Load and execute javascript code SYNCHRONOUSLY

有没有办法像同步 XMLHttpRequest 一样以同步方式加载和执行 javascript 文件?

我目前正在使用同步 XMLHttpRequest 然后对此进行评估,但是调试该代码非常困难......

谢谢你的帮助!

更新

我现在试过这个:

测试.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>

脚本.js

console.log("Hi");

输出:完成嗨

所以它不是同步执行的。 有没有让“嗨”先出现的想法?

更新 2其他示例

test.html(脚本标签内的代码)

var s = document.createElement("script");
s.setAttribute("src","script.js");
document.head.appendChild(s);
SayHi();

脚本.js

function SayHi(){
    console.log("hi");
}

输出:未捕获的 ReferenceError:未定义 SayHi

如果你使用这个:

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

脚本.js

function SayHi() {
     console.log("hi");
}

sayhi.js :

SayHi();

所有在 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);
}

从一个类似的问题( 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脚本调用的代码需要在它自己的<script>或者需要在window.onload()事件中。

您的脚本确实同步执行

如果放在一起,您的代码是:

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. HEAD正在被解析,它的SCRIPT子标签被解析和执行。 此执行向BODY标记添加了一个尚未解析的元素。
  3. 解析器移至BODY并解析其内容(新添加的SCRIPT标记),然后加载脚本并执行其内容。

SCRIPT元素仅在您的页面被解析并已在浏览器中呈现后添加时才会立即执行。 在你的情况下,情况并非如此。 第一个脚本立即执行,动态添加的脚本在解析到达时执行。

您可以在它们之间同步异步操作。 创建递归函数来表示一个循环,并在上一个完成时调用下一个操作。 以下函数使用类似的技术按顺序导入脚本。 它等待一个脚本被加载,如果没有错误继续下一个。 如果发生错误,它会调用带有错误事件的回调函数,如果没有错误 - 在加载所有脚本后使用 null 调用相同的回调函数。 它还使用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();
}

您可以在包含 js 文件时使用“defer”属性。

<script defer="defer" src="contact/js/frontend/form.js"></script>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM