为什么浏览器不解析由AJAX加载的文件中的JS代码?


Why doesn't browser parse the JS code in the file loaded by AJAX?

我有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是异步的。您的代码试图在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调用是同步的。您可以为<script>标签解析返回的HTML,并单独处理它们,但这并不漂亮:

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这样的库,它可以自动为您处理这个问题(以及许多其他问题!)。

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

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

我发现了一个非常有趣的方法,但它的工作!

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);
}

和not:

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