【问题标题】:XMLHttpRequest calls not finishing before return statement so undefinedXMLHttpRequest 调用未在 return 语句之前完成,因此未定义
【发布时间】:2012-05-07 07:52:31
【问题描述】:

我正在尝试计算我正在查询的数据库中有多少项目。它是第三方的,所以它是跨域 XMLHttpRequests,但我在 Chrome 扩展中创建该方法,并且 manifest.json 中的权限位让它运行良好。

我似乎遇到的问题是:在 XMLHttpRequests 从外部服务器返回之前,我正在遍历一个类别列表并计算每个类别的数量。这些方法通过按下 id="countButton" 的按钮来启动。这是相关的 javascript/jQuery:

//simple listener for the button
document.getElementById('countButton').addEventListener('click', function() runTotalCount()}, true);

//loops through a list of categories in a drop down with values 0-36
function runTotalCount(){
    var sum = 0;
    $('#categorySelect option').each(function(){
        var value = $(this).val();
        sum += retrieveCategoryCount(value);
        alert("New Sum = " + sum);
    });
    var total = "<p>Total items in Sum is " + sum + "</p>";
    document.getElementById('results').innerHTML = total;
}

//actually makes the request and sums the items count for each category
//the server response is a json with an alphabetized "items" per category
function retrieveCategoryCount(num){
    var sum = 0;
    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function(){
        if (xhr.readyState == 4 && xhr.status == 200){
            var str = xhr.responseText;
            alert("str = " + str);
            var json = $.parseJSON(str);
            alert("JSON = " + json);
            for(item in json.alpha){
                alert("items count = " + json.alpha[item].items);
                sum += json.alpha[item].items;
            }
        alert("Category Sum = " + sum);
        return sum;
        }
    }
    xhr.open(
        "GET",
        "http://services.runescape.com/m=itemdb_rs/api/catalogue/category.json?category=" + num,
        true);
    xhr.send(null);
}

因为它是 onreadystate 中的内容,retrieveCategoryCount 永远不会被调用,因为在函数完成时 XMLHttpRequests 仍然处于挂起状态。在同步调用中,alert("Category Sum = " + sum); 返回正确的数字,但它正下方的函数返回 NaN(我宁愿不挂断浏览器,但我更喜欢异步解决方案)。

需要更改哪些内容才能正确获取项目计数?提前致谢。

更新: 我还尝试了retrieveCategoryCount 的代码:

function retrieveCategoryCount(num){
    var sum = 0;
    $.getJSON("http://services.runescape.com/m=itemdb_rs/api/catalogue/category.json?category=" + num, function(data){
        for(item in data.alpha){
            alert("items count = " + data.alpha[item].items);
            sum += data.alpha[item].items;
        }
    alert("Category Sum = " + sum);
    return sum;
    });
}

这里的问题是回调永远不会运行,因为在从函数返回的值被添加到“sum”时,请求仍然处于挂起状态。

【问题讨论】:

  • 你的脚本中有很多东西需要修复......你使用 jQuery 但只在几个小地方利用它的力量 - 做一些工作你至少可以完成一半这段代码
  • 任何建议都将不胜感激。我过去使用过 $.ajax 和 $.getJSON,但我已经在扩展中使用了其他类似的代码,所以我想我会保持一致。
  • 我可能会建议您将所有选择的选项传递给服务器 - 也许是 JSON 或 XML 或纯文本 - 让服务器计算总数,然后对屏幕进行一次更新
  • 我添加了一个示例答案 - 它不是最终代码,需要更新......您的代码不起作用的原因是因为 AJAX 回调在以后执行 - 其余的函数内的代码立即执行
  • 我不相信我可以将 POST 用于跨域请求。我发送的网址有category=#,其中# 是您想要的任何类别编号(0-36)。我不认为我可以将一个数组发布到服务器并让它知道如何处理它。

标签: javascript jquery google-chrome-extension xmlhttprequest


【解决方案1】:

您可以将异步调用完成后应该发生的代码放入回调函数中,并将其传递给您的异步函数,然后让它回调。

var sum = 0,
    setTotalCount = function(data){ 
        .. stuff to set the dom element based on callback
    };
$('#categorySelect option').each(function(){
    var value = $(this).val();
    retrieveCategoryCount(value, setTotalCount);
});


function retrieveCategoryCount(num, callback){
var sum = 0;
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
    if (xhr.readyState == 4 && xhr.status == 200){
        var str = xhr.responseText;
        alert("str = " + str);
        var json = $.parseJSON(str);
        alert("JSON = " + json);
        for(item in json.alpha){
            alert("items count = " + json.alpha[item].items);
            sum += json.alpha[item].items;
        }
    alert("Category Sum = " + sum);
       callback(sum); // callback the function you passed in
    }
}
xhr.open(
    "GET",
    "http://services.runescape.com/m=itemdb_rs/api/catalogue/category.json?category=" + num,
    true);
xhr.send(null);
}

【讨论】:

  • 当我尝试这个时,运行的唯一警报是alert("New Sum = " + sum);,因为在函数调用时请求仍然处于未决状态。另外:我对javascript有点陌生,所以我不知道最后的callback(num);应该如何解决这个问题。
  • 好吧,在这一点上,我相信@ManseUK 的 ajax 答案可能是您在工作方向方面的最佳选择,但关于回调将如何提供帮助,重点是将所有代码放入您的想要在总数被处理到回调函数之后运行。这不是特定于 javascript 的事情。基本上,在您的原始代码中,您正在调用 async 函数,当它愉快地完成它的事情时,您的下一行将被执行。您真的希望在异步调用完成之前不执行下一行。
【解决方案2】:

您传递给onreadystatechange 的回调函数不是retrieveCategoryCount。它的返回值丢失了,因为该函数仅在响应 readystatechange 事件时被调用。

回调中的数据做你需要做的事情。不要试图返回数据。

【讨论】:

    猜你喜欢
    • 2016-04-16
    • 2014-05-11
    • 1970-01-01
    • 1970-01-01
    • 2019-03-16
    • 2019-03-07
    • 1970-01-01
    • 2013-05-05
    • 1970-01-01
    相关资源
    最近更新 更多