AJAX响应文本未定义

时间:2015-04-13 06:45:47

标签: javascript ajax

我正在关注以下2个帖子:

  1. Ajax responseText comes back as undefined
  2. Can't return xmlhttp.responseText?
  3. 我以相同的方式实现了代码。但我得到了

      

    undefined不是函数

    无论我在我的代码中使用callback()函数。

    CODE:

    function articleLinkClickAction(guid,callback){
    
        var host = window.location.hostname;
        var action = 'http://localhost:7070/assets/find';
        var url = action + '?listOfGUID=' + guid.nodeValue;
        console.log("URL "+url);
        xmlhttp = getAjaxInstance();
        xmlhttp.onreadystatechange = function() 
        {
            if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
    
                var response = JSON.parse(xmlhttp.responseText);
                console.log(response);
                console.log(xmlhttp.responseText);
                callback(null, xmlhttp.responseText);// this is line causing error
            }
            else{
                callback(xmlhttp.statusText);// this is line causing error
            }
        };
        xmlhttp.open("GET", url, true);
        xmlhttp.send(null);
    }
    

    我从这段代码中调用它:

    var anchors =  document.getElementsByTagName("a");
            var result = '';
            for(var i = 0; i < anchors.length; i++) {
                var anchor = anchors[i];
    
                var guid = anchor.attributes.getNamedItem('GUID');
                if(guid)
                {
                    articleLinkClickAction(guid,function(err, response) { // pass an anonymous function
                        if (err) {
                            return "";
    
                        } else {
                            var res =  response;
                            html = new EJS({url:'http://' + host + ':1010/OtherDomain/article-popup.ejs'}).render({price:res.content[i].price});
                            document.body.innerHTML += html;
                        } 
                    });
                }
            }
    

1 个答案:

答案 0 :(得分:0)

您正在为xmlhttp使用单个全局变量,并尝试同时运行多个ajax调用。因此,每次连续的ajax调用都将覆盖先前的ajax对象。

我建议在var声明前添加xmlhttp,使其成为函数中的局部变量,这样每个ajax请求都可以有自己独立的状态。

function articleLinkClickAction(guid,callback){

    var host = window.location.hostname;
    var action = 'http://localhost:7070/assets/find';
    var url = action + '?listOfGUID=' + guid.nodeValue;
    console.log("URL "+url);
    // add var in front of xmlhttp here to make it a local variable
    var xmlhttp = getAjaxInstance();
    xmlhttp.onreadystatechange = function() 
    {
        if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {

            var response = JSON.parse(xmlhttp.responseText);
            console.log(response);
            console.log(xmlhttp.responseText);
            callback(null, xmlhttp.responseText);// this is line causing error
        }
        else{
            callback(xmlhttp.statusText);// this is line causing error
        }
    };
    xmlhttp.open("GET", url, true);
    xmlhttp.send(null);
}

将来,您应该考虑使用Javascript's strict mode因为这些“偶然”全局变量在严格模式下是不允许的,并且会报告错误以使您明确地将所有变量声明为本地或全局变量(无论您想要哪个)

我不能说这是否是阻止您的代码工作的唯一错误,但它肯定是一个重要的错误,正在妨碍正常运行。


这是另一个重要问题。在您的真实代码中(在私人聊天中看到),您正在使用:

document.body.innerHTML += html

在HTMLCollection迭代的中间,如下所示:

var anchors = document.getElementsByTagName("a");

在此代码中,anchors将是一个实时HTMLCollection。这意味着只要在文档中添加或删除锚元素,它就会动态更改。但是,每次执行document.body.innerHTML += html时,都会从头开始重新创建整个身体元素,从而完全更改anchors HTMLCollection。首先执行document.body.innerHTML += html只是一种不好的做法。相反,您应该将新元素附加到现有DOM。我不知道html中到底是什么,但你应该只创建一个div,将HTML放入其中并附加这样的div:

var div = document.createElement("div");
div.innerHTML = html;
document.body.appendChild(div);

但是,这还不是全部,因为如果这个新HTML包含更多<a>标记,那么anchors中的实时HTMLCollection仍会发生变化。

我建议更改此代码块:

    var anchors =  document.getElementsByTagName("a");
    var result = '';
    for(var i = 0; i < anchors.length; i++) {
        var anchor = anchors[i];

        var guid = anchor.attributes.getNamedItem('GUID');
        if(guid)
        {
            articleLinkClickAction(guid,function(err, response) { // pass an anonymous function
                if (err) {
                    return "";

                } else {
                    var res =  response;
                    html = new EJS({url:'http://' + host + ':1010/OtherDomain/article-popup.ejs'}).render({price:res.content[i].price});
                    document.body.innerHTML += html;
                } 
            });
        }
    }

到此:

(function() {
    // get static copy of anchors that won't change as document is modified
    var anchors = Array.prototype.slice.call(document.getElementsByTagName("a"));

    var result = '';
    for (var i = 0; i < anchors.length; i++) {
        var anchor = anchors[i];

        var guid = anchor.attributes.getNamedItem('GUID');
        if (guid) {
            articleLinkClickAction(guid, function (err, response) { // pass an anonymous function 
                if (err) {
                    //return ""; 
                    console.log('error : ' + err);
                } else {
                    var res = response;
                    var html = new EJS({
                        url: 'http://' + host + ':1010/OtherDomain/article-popup.ejs'
                    }).render({
                        price: res.content[i].price
                    });
                    var div = document.createElement("div");
                    div.innerHTML = html;
                    document.body.appendChild(html);
                }
            });
        }
    }
})();

这会做出以下更改:

  1. 将代码包含在IIFE(自执行函数)中,因此代码块中声明的变量不是全局的。

  2. document.body.innerHTML += html更改为使用document.body.appendChild(),以避免每次都重新创建所有DOM元素。

  3. 声明var html所以它是一个局部变量,而不是另一个偶然的全局变量。

  4. 使用document.getElementsByTagName("a")Array.prototype.slice.call()复制结果,因此数组不会随着文档的修改而改变,从而允许我们准确地迭代它。