是否可以使用XMLHttpRequest评估JavaScript代码


is it possible to evaluate JavaScript code using XMLHttpRequest

我正试图使用这个AJAX请求来调用一个文件,其中一些PHP运行正常,而一些JavaScript运行不正常。有什么想法吗?

function showpart2(){
    if(window.XMLHttpRequest){
        xmlhttp = new XMLHttpRequest();
        xmlhttp.open("GET","atuamae.org/parte2-encomendar.php",false);
        xmlhttp.send(null);
    }
    document.getElementById('part2').innerHTML = xmlhttp.responseText;
    eval(xmlhttp.responseText.getElementById('part2').innerHTML)
    setTimeout('showpart2()',15000);
}
showpart2();

示例代码的一个大问题是,使XMLHttpRequest.send同步意味着所有JS执行都必须暂停,同时等待接收到请求。没有理由不使用异步调用。

异步调用可以提高响应能力,但它们不能提供协调,这意味着在准备好所需的数据之前,任务不会运行。协调异步代码的标准方法是将一个函数传递给异步函数,该函数在执行时执行依赖于数据的其余计算。该功能的技术名称为";"延续";,它只是一个函数,表示从给定点向前的其余计算。也就是说,转向:

f1();
f2();
async();
f3();
f4();

进入:

f1();
f2();
async(function() {
    f3();
    f4();
});

因为你在传递一个延续,这被称为";延续传球风格";。XMLHttpRequest是一种特殊情况,因为您没有将函数传递给异步函数,而是将其设置为XHR对象上readystatechange事件的侦听器。也就是说,您将延续指定给xmlhttp.onreadystatechange

还有一些改进需要改进。首先,添加错误检测。XHR实例的status属性保存HTTP状态,您可以使用它来检查错误。

正如许多其他人所提到的,eval可能会有问题,在有其他选择时应该避免。首先,您必须确保字符串来自可信来源。这里eval的特殊问题是在与调用eval相同的上下文中评估脚本。如果eval发生在函数内部,则脚本定义的任何内容在函数外部都不可见。如果您的脚本不需要定义任何东西(也永远不需要定义什么;始终考虑代码的未来(,则可以使用eval。否则,以脚本为内容动态创建一个脚本元素,并将其添加到文档中;您可以定义一个执行此操作的函数(请参阅下面示例中的globaleval(。

xmlhttp是一个全局变量,这是不好的。相反,将其声明为局部变量。

使用setInterval,而不是用于一次性调用的setTimeout,它周期性地调用传递的函数。请注意,setTimeoutsetInterval可能需要比给定延迟更长的时间才能运行,尽管这在这里应该不是问题。

(function () {
    // keep variable from polluting global namespace
    var showpart2Interval = 0,
        scriptElt = {parentNode: {removeChild: function() {}}};
        
    function globaleval(script) {
        scriptElt.parentNode.removeChild(scriptElt);
        scriptElt = document.createElement('script');
        scriptElt.type = 'text/javascript'
        scriptElt.appendChild(document.createTextNode(script));
        document.body.appendChild(scriptElt);
    }
    function showpart2(){
        var xmlhttp = new XMLHttpRequest();
        xmlhttp.open("GET","atuamae.org/parte2-encomendar.php",false);
        xmlhttp.onreadystatechange = function() {
            if (xmlhttp.readyState == 4) {
                if (200 <= xmlhttp.status && xmlhttp.status < 300) {
                    globaleval(xmlhttp.responseText);
                } else {
                    // HTTP error
                    ...
                }
            }
        }
        xmlhttp.send(null);
    }
    
    function startShowpart2() {
        if (window.XMLHttpRequest && !showpart2Interval) {
            showpart2();
            showpart2Interval = setInterval(showpart2, 15000);
        }
    }
    function stopShowpart2() {
        clearInterval(showpart2Interval);
        showpart2Interval = 0;
    }
    
    window.startShowpart2 = startShowpart2;
    window.stopShowpart2 = stopShowpart2;
})();
startShowpart2();

如果您不关心自己实现所有这些,请让jQuery来承担重任。知道如何自己动手是件好事,但(对于生产代码(使用具有标准接口的标准库可以在许多方面加快开发。

另请参阅

  • Javascript:设置函数的顺序

您需要实际评估JS标记(手动,通过eval或通过DOM插入(。像jQuery这样的库可以帮你做到这一点,但如果你需要使用自定义解决方案,你也需要添加它。

您编写:

xmlhttp.responseText.getElementById("第2部分"(

responseText是一个字符串,不会有任何getElementById方法。您可以使用xmlhttp.responseXML.getElementById("part2"(,也可以使用字符串方法提取第二部分。

像Adam Rackis一样,我建议你使用$.ajax。yyy很容易尝试……但如果它不是你的选择,这里有一个函数,用于进行ajax调用,并在IE和Firefox中工作,如果你不能使用Jquery,我建议Chrome。函数中的问题在IE中不起作用,因为它没有xmlhttprequest对象。希望这对你有帮助。

function newAjaxObject()
{
    var oHttp=false;
    var asParsers=[
         "Msxml2.XMLHTTP.5.0", 
         "Msxml2.XMLHTTP.4.0", 
         "Msxml2.XMLHTTP.3.0", 
         "Msxml2.XMLHTTP", 
         "Microsoft.XMLHTTP"
    ];
    if ( !oHttp && typeof XMLHttpRequest != 'undefined')
    {
        oHttp=new XMLHttpRequest();
    }
 if( !oHttp){
    for (var iCont=0; !oHttp && iCont < asParsers.length; iCont++)
    {
        try
        {
            oHttp=new ActiveXObject(asParsers[iCont]);
        }
        catch(e)
        {
            oHttp=false;
        }
    }
}
   return oHttp;
}