ajax 每个循环中的调用均未按预期运行

ajax call in each loop functions as not expected

我有一个函数可以输出一个名为 DisplayComments(comments) 的数组。在此函数中,我进行了 ajax 调用以检索与 comments 关联的 replies

当ajax为运行取回replies,从webapicontroller返回数组后,代码跳出ajax然后转到 each loop 的最后一行,即 $('#div_ListOfComments').append(replies);。然后它返回到循环的第一行,即 var cid = comment.CommentId; 并继续下一个注释项。然后,ajax 调用发生在第二个 comment 上,它的行为方式相同。在所有 commentseach loop 完成之前,它永远不会访问 ajax 调用的 Success 状态。然后,它移动到成功部分并为每个 reply 项目运行一次代码以将它们显示在表单上。

但是,我需要在每个评论下面附加 replies,换句话说,我需要在 comment 之后将 replies 附加到 $('#div_ListOfComments')附加。但是,下面说明的代码未按预期方式运行。它附加所有评论。然后附加回复。谁能看出下面的代码有什么问题吗?

    function LoadCommentsForPost(postid) {
        jQuery.support.cors = true;
        $.ajax({
            url: '/api/Comment/GetCommentsByPost?pid=' + postid,
            type: 'GET',
            contentType: "application/json; charset=utf-8;",
            dataType: 'json',
            success: function (response) {                 

            },
            error: function (x, y, z) {
                alert(x + '\n' + y + '\n' + z);
            },
            complete: function (jqXHR, textStatus) {
                var comments = JSON.parse(jqXHR.responseText);
                comments = comments["$values"];
                DisplayComments(comments);
            }
        });
    }

    function DisplayComments(comments) {

        $('#div_ListOfComments').html('');
        $.each(comments, function (index, comment) {
            //the current comment is appended to $('#div_ListOfComments')

            var cid = comment.CommentId;
            var replies;
            $.ajax({
                url: '/api/Reply/GetRepliesByComment?cid=' + cid,
                type: 'GET',
                contentType: "application/json; charset=utf-8;",
                dataType: 'json',
                success: function (response) {
                    //VS break-point works just before here
                    //and I see a valid return value from VS
                    //the program continue to work outside of the ajax
                    //with this line below: $('#div_ListOfComments').append.....
                },
                error: function (x, y, z) {
                    alert(x + '\n' + y + '\n' + z);
                }
            });

            $('#div_ListOfComments').append(replies);
        });
    }

Ajax 是异步的。对 $.ajax() 的调用只会启动 ajax 调用。然后是执行后的代码行。在服务器 returns 响应 ajax 调用之后,才会调用 success 回调。

您也不能指望 ajax 回复会按照您提出请求的顺序返回。

你可以这样做:

function DisplayComments(comments) {
    $('#div_ListOfComments').html('');
    $.each(comments, function (index, comment) {
        var cid = comment.CommentId;

        // Append the comment to $('#div_ListOfComments').
        // Append an empty div to $('#div_ListOfComments') that will hold the replies,
        // giving it an id based on cid.

        $.ajax({
            url: '/api/Reply/GetRepliesByComment?cid=' + cid,
            type: 'GET',
            contentType: "application/json; charset=utf-8;",
            dataType: 'json',
            success: function (response) {
                // Put the replies in the div with the id based on cid.
                // cid will have the correct value because this is a closure.
            }
        });
    });
}

另一种方法是将评论和回复保留在数据中,直到最后一次 ajax 调用 returns,然后将它们全部添加到页面。

function DisplayComments(comments) {
    var replies = {};
    var deferreds = $.map(comments, function(comment) {
        var cid = comment.CommentId;
        return $.ajax({
            url: '/api/Reply/GetRepliesByComment?cid=' + cid,
            type: 'GET',
            contentType: "application/json; charset=utf-8;",
            dataType: 'json',
            success: function(reply) {
                replies[cid] = reply;
            }
        });
    });

    // This executes the function when all the ajax calls have returned.
    $.when.apply($, deferreds).then(function() {
        $('#div_ListOfComments').html('');
        $.each(comments, function(i, comment) {
            var reply = replies[comment.id];
            $('#div_ListOfComments').append(comment.text).append(reply);
        });
    });
}

jsfiddle

。 此外,我建议您更改级联 ajax 调用的使用。您可以使用 deferred/promise 方法。

您的代码将如下所示

function LoadCommentsForPost(){
    jQuery.support.cors = true;
    return $.ajax({
        url: '/api/Comment/GetCommentsByPost?pid=' + postid,
        type: 'GET',
        contentType: "application/json; charset=utf-8;",
        dataType: 'json'
    });
}
function LoadCommentsForPostError(x, y, z) {
    alert(x + '\n' + y + '\n' + z);
}
function RetrievedComments(jqXHR, textStatus)
{
    var comments = JSON.parse(jqXHR.responseText);
    comments = comments["$values"];
    DisplayComments(comments);
}
function DisplayComments(comments) {
    $('#div_ListOfComments').html('');
    $.each(comments, function (index, comment) {
        var cid = comment.CommentId;

        // Append the comment to $('#div_ListOfComments').
        // Append an empty div to $('#div_ListOfComments') that will hold the replies,
        // giving it an id based on cid.

        $.ajax({
            url: '/api/Reply/GetRepliesByComment?cid=' + cid,
            type: 'GET',
            contentType: "application/json; charset=utf-8;",
            dataType: 'json',
            success: function (response) {
            // Put the replies in the div with the id based on cid.
            // cid will have the correct value because this is a closure.
            }
        });
    });
}

$.when(LoadCommentsForPost()).then(RetrievedComments, LoadCommentsForPostError);

更多信息在 $.when documentation