【问题标题】:Why doesn't browser parse the JS code in the file loaded by AJAX?为什么浏览器不解析 AJAX 加载的文件中的 JS 代码?
【发布时间】:2011-12-30 00:32:32
【问题描述】:

我有 2 个文件,第一个文件有一些 HTML 和一部分 JS。第二个文件是主文件,它通过 XmlHttpRequest 加载第一个文件。

第一个文件是这样的:

<div>
  My HTML contents
</div>

<script id="my_js_block">
function my_function() {
  alert(9);
}
</script>

第二个文件是这样的:

<div id="div_ajax_content">
  &nbsp;
</div>

<script>
function load_ajax_content() { 
  //synchronously with XmlHttpRequest(...,...,false);
  //...load and throw the first file into 'div_ajax_content'
}

load_ajax_content();
my_function();  <-- fails here
</script>

如何解决这个问题?

【问题讨论】:

  • 我刚刚编辑了问题。
  • 我猜你不能调用这个函数,因为 AJAX - 调用是异步的。这意味着您必须等待通话结束才能拨打my_function()

标签: php javascript html ajax xmlhttprequest


【解决方案1】:

在 Kolink 之后,我发现了一个非常有趣的方法,但它确实有效!

load_ajax_contents();
eval(document.getElementById("my_js_block").innerHTML);
my_function();

但是,为了使这些函数由 'eval()' 全局进行评估,第一个文件中的所有函数都必须声明为变量,如下所示:

//this works!
my_function = function() {
  alert(9);
}

而不是:

//this makes the function nested in the context where eval() is called
function my_function() { 
  alert(9);
}

也不是:

//this makes the variable local to the context where eval() is called
var my_function = function() {
  alert(9);
}

【讨论】:

    【解决方案2】:

    Ajax 是异步的。您的代码尝试在 XMLHttpRequest 完成之前调用 my_function()。改为这样做:

    <script>
    function load_ajax_content() {
        //...load and throw the first file into 'div_ajax_content'
        // then,
        my_function();
    }
    
    load_ajax_content();
    </script>
    

    好的,现在您的 ajax 调用是同步的。可以解析返回的 HTML 中的&lt;script&gt; 标签,分别处理,但并不美观:

    function load_ajax_content() {
        //...load and throw the first file into 'div_ajax_content'
        // then grab the script nodes one-by-one
        var scriptElts = document.getElementById('div_ajax_content').getElementsByTagName('script'),
            scriptElt,
            propName; // http://www.quirksmode.org/dom/w3c_html.html#t07
    
        if (scriptElts.length) {
            propName = scriptElts[0].textContent ? 'textContent' : 'innerText';
        }
    
        for (var i=0; i<scriptElts.length; i++) {
            scriptElt = document.createElement('script');
            scriptElt[propName] = scriptElts[i][propName];
            document.body.appendChild(scriptElt);
        }
    
        // finally,
        my_function();
    }
    

    ...或者您可以使用像 jQuery 这样的库,它会自动为您处理这个确切的问题(以及许多其他问题!)。

    【讨论】:

    • 我刚刚修改了这个问题。它同步加载
    • @PaulDinh 尽管如此,在您给定的示例中,您在load_ajax_content() 之后调用my_function(),而请求仍在“进行中”。尝试将 my_function() 调用移动到 load_ajax_content 的末尾 - 正如 Matt 建议的那样,它应该可以工作。
    • @PaulDinh 啊,我明白了,对不起。今天通过那个例子又学到了一些东西:)
    • @MattBall 但是从脚本中添加元素太痛苦了,我决定使用 eval()
    • @PaulDinh 但是请不要使用它,除非您可以绝对确定用户无法输入传递给 eval() 的内容
    【解决方案3】:

    通过 innerHTML 添加脚本不会运行该脚本。因此您的函数没有被定义,因此失败。

    相反,我建议分别加载 HTML 和 JS,并使用 DOM 方法附加 JS 以将 &lt;script&gt; 标记放在页面上,或 eval() 执行返回的文件内容。

    【讨论】:

    • eval() 是一种解决方案,但不知道有没有更纯粹的方法
    • eval() 可以在这里使用,因为 JS 是一种解释性语言(您不需要编译它 - 浏览器会提高性能,但它不是必需的),并且因为它是一种时间的事。如果你要在一个大循环中使用eval,那会很糟糕,但对于像这样的一次性位就很好了。
    • 如果我调用 eval("function my_func(){}") 两次会失败吗? (可能是“函数重定义”之类的错误?)
    • 我不这么认为。虽然,我总是用my_func = function() {...}; 声明函数
    • 您将函数声明为变量的方式很棒,它使这些函数在由 eval() 评估时变为全局,而不是在调用 'eval()' 的上下文中成为“本地”。 tks :)
    猜你喜欢
    • 2020-04-13
    • 2015-06-24
    • 1970-01-01
    • 2015-04-19
    • 1970-01-01
    • 1970-01-01
    • 2020-03-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多