繁体   English   中英

循环内的Ajax调用需要顺序响应

[英]Ajax calls inside loop need sequential responses

我需要进行3个或更少的ajax调用,并且响应必须按照请求的顺序添加到dom上。

我具有以下功能,但是问题是,当我将它们附加到dom时,它们得到的响应不一定正确顺序。

我不想使用async:false属性,因为它会阻塞UI,这当然会提高性能。

mod.getArticles = function( ){
    //mod.vars.ajaxCount could start at 0-2
    for( var i = mod.vars.ajaxCount; i < 3; i++ ){
        //mod.vars.pushIds is an array with the ids to be ajaxed in
        var id = mod.vars.pushIds[i];

        $.ajax({
            url: '/ajax/article/' + id + '/',
            type: "GET",
            dataType: 'HTML',
            error: function() {
                console.error('get article ajax error');
            }
        }).done( function( data ) {
            if (data.length) {
                mod.appendArticle( data );
            } else {
                console.error('get article ajax output error');
            }
        });
    }
};

您需要根据例如您拥有的i变量将文章附加到某个位置。 或者,您可以等待所有请求,然后按顺序附加它们。 像这样:

mod.getArticles = function( ){
    var load = function( id ) {
        return $.ajax({
            url: '/ajax/article/' + id + '/',
            type: "GET",
            dataType: 'HTML',
            error: function() {
                console.error('get article ajax error');
            });
        };
    var onDone = function( data ) {
            if (data.length) {
                mod.appendArticle( data );
            } else {
                console.error('get article ajax output error');
            }
        };
    var requests = [];
    for( var i = mod.vars.ajaxCount; i < 3; i++ ){
        requests.push(load(mod.vars.pushIds[i]));
    }

    $.when.apply(this, requests).done(function() {
        var results = requests.length > 1 ? arguments : [arguments];
        for( var i = 0; i < results.length; i++ ){
            onDone(results[i][0]);
        }
    });
};

这是一个使用i的示例,当它们全部加载完成时,它们以适当的顺序附加到它们:

mod.getArticles = function( ){
    // initialize an empty array of proper size
    var articles = Array(3 - mod.vars.ajaxCount);
    var completed = 0;
    //mod.vars.ajaxCount could start at 0-2
    for( var i = mod.vars.ajaxCount; i < 3; i++ ){
        // prevent i from being 3 inside of done callback
        (function (i){
            //mod.vars.pushIds is an array with the ids to be ajaxed in
            var id = mod.vars.pushIds[i];
            $.ajax({
                url: '/ajax/article/' + id + '/',
                type: "GET",
                dataType: 'HTML',
                error: function() {
                    console.error('get article ajax error');
                }
            }).done( function( data ) {
                completed++;
                if (data.length) {
                    // store to array in proper index
                    articles[i - mod.vars.ajaxCount] = data;
                } else {
                    console.error('get article ajax output error');
                }
                // if all are completed, push in proper order
                if (completed == 3 - mod.vars.ajaxCount) {
                    // iterate through articles
                    for (var j = mod.vars.ajaxCount; j < 3; j++) {
                        // check if article loaded properly
                        if (articles[j - mod.vars.ajaxCount]) {
                            mod.appendArticle(articles[j - mod.vars.ajaxCount]);
                        }
                    }
                }
            });
        }(i));
    }
};
var success1 = $.ajax...
var success2 = $.ajax...
var success3 = $.ajax...
$.when(success1, success2, success3).apply(ans1, ans2, ans3) {
finalDOM = ans1[0]+ans2[0]+ans3[0];
}

检查以获取更多参考。 这仍然是异步的,但是它等待所有它们完成。 您已经知道调用的顺序,就像通​​过代码完成的那样,因此请相应地添加dom元素。

尝试将mod.vars数组中的项目用作索引; 设置为$.ajaxSettings id属性,在响应数组中的this.id索引处设置返回的data 完成所有请求后, results array应与mod.vars值的顺序相同。

var mod = {
    "vars": [0, 1, 2]
};

mod.getArticles = function () {
    var results = [];
    var ids = this.vars;
    var request = function request(id) {
            return $.ajax({
                type: "GET",
                url: "/ajax/article/" + id + "/",
                // set `id` at `$.ajaxSettings` ,
                // available at returned `jqxhr` object
                id: id  
            })
            .then(function (data, textStatus, jqxhr) {
                // insert response `data` at `id` index within `results` array
                console.log(data); // `data` returned unordered
                // set `data` at `id` index within `results
                results[this.id] = data;
                return results[this.id]
            }, function (jqxhr, textStatus, errorThrown) {
                console.log("get article ajax error", errorThrown);
                return jqxhr
            });
    };

    return $.when.apply(this, $.map(ids, function (id) {
        return request(id)
    }))
    .then(function () {
        $.map(arguments, function (value, key) {
            if (value.length) {
                // append `value`:`data` returned by `$.ajax()`,
                // in order set by `mod.vars` items:`id` item at `request`
                mod.appendArticle(value);
            } else {
                console.error("get article ajax output error");
            };
        })
    });

};

mod.getArticles();

jsfiddle http://jsfiddle.net/6j7vempp/2/

仅依靠闭包的解决方案将在一定程度上发挥作用。 他们将以正确的顺序一致地追加单个mod.getArticles()调用的文章。 但是在第一个电话完全满足之前,请考虑第二个电话。 由于该过程的异步性,可以想象第二个调用的文章集可以附加在第一个调用之前。

更好的解决方案将保证即使对mod.getArticles()调用的快速启动序列也可以:

  • 以正确的顺序附加每个电话的文章
  • 以正确的顺序附加所有文章集

一种解决方法是针对每篇文章:

  • 同步将容器(div)附加到DOM并保留对其的引用
  • 到达时以异步方式将内容填充到容器中。

为此,您将需要修改mod.appendArticle()以接受第二个参数-对容器元素的引用。

mod.appendArticle = function(data, $container) {
    ...
};

为了方便起见,您还可以选择创建一个新方法mod.appendArticleContainer() ,该方法将创建一个div并将其附加到DOM并返回对其的引用。

mod.appendArticleContainer = function() {
    //put a container somewhere in the DOM, and return a reference to it.
    return $("<div/>").appendTo("wherever");
};

现在, mod.getArticles()仍然非常简单:

mod.getArticles = function() {
    //Here, .slice() returns a new array containing the required portion of `mod.vars.pushIds`.
    //This allows `$.map()` to be used instead of a more cumbersome `for` loop.
    var promises = $.map(mod.vars.pushIds.slice(mod.vars.ajaxCount, 3), function(id) {
        var $container = mod.appendArticleContainer();//<<< synchronous creation of a container
        return $.ajax({
            url: '/ajax/article/' + id + '/',
            type: "GET",
            dataType: 'HTML'
        }).then(function(data) {
            if (data.length) {
                mod.appendArticle(data, $container);//<<< asynchronous insertion of content
            } else {
                return $.Deferred().reject(new Error("get article ajax output error"));
            }
        }).then(null, function(e) {
            $container.remove();//container will never be filled, so can be removed.
            console.error(e);
            return $.when(); // mark promise as "handled"
        });
    });
    return $.when.apply(null, promises);
};

mod.getArticles()现在向其调用者返回完成承诺,并在必要时允许进一步链接。

而不是使用for循环。 在上一个函数的响应部分中调用您的函数。

    //create a global variable
        var counter = 0;

        function yourFunc(){

        mod.getArticles = function( ){
            //mod.vars.ajaxCount could start at 0-2
            //mod.vars.pushIds is an array with the ids to be ajaxed in
                var id = mod.vars.pushIds[counter ];

                $.ajax({
                    url: '/ajax/article/' + id + '/',
                    type: "GET",
                    dataType: 'HTML',
                    error: function() {
                        console.error('get article ajax error');
                    }
                }).done( function( data ) {
                    if (data.length) {
                        mod.appendArticle( data );
                    } else {
                        console.error('get article ajax output error');
                    }
        //increment & check your loop condition here, so that your responses will be appended in same order
         counter++;
         if (counter < 3)
              { yourFunc(); }
                });

        };
        }

我面临着同样的问题,我正在使用以下方式解决此问题。 只需使用异步获取明智的序列响应

<script type="text/javascript">
var ajax1 =  $.ajax({
      async: false, 
      url: 'url',
      type: 'POST',
      data: {'Data'},
    })
.done(function(response) {
        console.log(response);
});

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM