简体   繁体   English

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

[英]Ajax calls inside loop need sequential responses

I need to make 3 or less ajax calls, and the responses need to be appended to the dom in the same order they were requested. 我需要进行3个或更少的ajax调用,并且响应必须按照请求的顺序添加到dom上。

I have the following function, but the problem is that the responses that I get are not necessarily in the correct order when they get appended to the dom. 我具有以下功能,但是问题是,当我将它们附加到dom时,它们得到的响应不一定正确顺序。

I wouldn't want to use the async: false property because it blocks the UI and it's a performance hit of course. 我不想使用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');
            }
        });
    }
};

You need to append the article to a certain position, based on for example the i variable you have. 您需要根据例如您拥有的i变量将文章附加到某个位置。 Or you could wait for all of the requests and then append them in order. 或者,您可以等待所有请求,然后按顺序附加它们。 Something like this: 像这样:

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]);
        }
    });
};

Here is an example using i to append them in the proper order when they all finish loading: 这是一个使用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];
}

Check this for more reference. 检查以获取更多参考。 This is still async, but it waits for all of them to complete. 这仍然是异步的,但是它等待所有它们完成。 You know the order of invocation already, as its done through your code, so add the dom elements accordingly. 您已经知道调用的顺序,就像通​​过代码完成的那样,因此请相应地添加dom元素。

Try utilizing items within mod.vars array as indexes; 尝试将mod.vars数组中的项目用作索引; to set as id property of $.ajaxSettings , set returned data at this.id index within an array of responses. 设置为$.ajaxSettings id属性,在响应数组中的this.id索引处设置返回的data results array should be in same order as mod.vars values when all requests completed. 完成所有请求后, 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/ jsfiddle http://jsfiddle.net/6j7vempp/2/

Solutions that rely solely on closures will work up to a point. 仅依靠闭包的解决方案将在一定程度上发挥作用。 They will consistently append the articles of a single mod.getArticles() call in the correct order. 他们将以正确的顺序一致地追加单个mod.getArticles()调用的文章。 But consider a second call before the first is fully satisfied. 但是在第一个电话完全满足之前,请考虑第二个电话。 Due to asynchronism of the process, the second call's set of articles could conceivably be appended before the first. 由于该过程的异步性,可以想象第二个调用的文章集可以附加在第一个调用之前。

A better solution would guarantee that even a rapid fire sequence of mod.getArticles() calls would : 更好的解决方案将保证即使对mod.getArticles()调用的快速启动序列也可以:

  • append each call's articles in the right order 以正确的顺序附加每个电话的文章
  • append all sets of articles in the right order 以正确的顺序附加所有文章集

One approach to this is, for each article : 一种解决方法是针对每篇文章:

  • synchronously append a container (a div) to the DOM and keep a reference to it 同步将容器(div)附加到DOM并保留对其的引用
  • asynchronously populate the container with content when it arrives. 到达时以异步方式将内容填充到容器中。

To achieve this, you will need to modify mod.appendArticle() to accept a second parameter - a reference to a container element. 为此,您将需要修改mod.appendArticle()以接受第二个参数-对容器元素的引用。

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

For convenience, you may also choose to create a new method, mod.appendArticleContainer() , which creates a div, appends it to the DOM and returns a reference to it. 为了方便起见,您还可以选择创建一个新方法mod.appendArticleContainer() ,该方法将创建一个div并将其附加到DOM并返回对其的引用。

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

Now, mod.getArticles() is still very simple : 现在, 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() now returns a promise of completion to its caller, allowing further chaining if necessary. mod.getArticles()现在向其调用者返回完成承诺,并在必要时允许进一步链接。

Instead of using a for loop. 而不是使用for循环。 Call your function in response part of previous function. 在上一个函数的响应部分中调用您的函数。

    //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(); }
                });

        };
        }

I'm faced same problem i'm solve this problem using following way. 我面临着同样的问题,我正在使用以下方式解决此问题。 just use async for get sequence wise response 只需使用异步获取明智的序列响应

<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