匹配嵌套的ajax调用的结果

时间:2015-09-12 15:08:36

标签: jquery ajax

如何匹配两个嵌套的ajax调用的结果?

一个例子:第一个调用获取一个url列表,并且每个调用的嵌套一个将检索页面的标题。会发生的是,当我进行第二次通话时,第一次通话会在后台继续,并且找不到我的结果。任何解决方案?

代码:

$.ajax({
        dataType : "json",
        url : queryUrlDoc,
        success : function(json) {
            queryResults = json.results.bindings;
            var title;
            var temp = [];
            for(var i in queryResults){
                var url = queryResults[i]['doc'].value;
                $.ajax({
                    url: url,
                    type: 'get',
                    success: function(data) {
                        title = data;
                        var item = {
                          'url' : url,
                          'title': title
                        };
                        temp.push(item);
                    } 
                 });
            }
            var titolo;
            for(var i in temp) {
                uri = temp[i]['url'];
                titolo = temp[i]['title'];
                //do stuff
            }
        },
        error: function(){
            alert("fail");
        }
    });

不幸的是,第二个'即使第一个人没有完成它的工作,周期也会开始......

4 个答案:

答案 0 :(得分:3)

在处理之前,您是否需要等待所有ajax调用返回?如果没有,您可以执行以下操作:

$.ajax({
    url: queryUrlDoc,
    dataType: 'json',
    success: function(json) {
        $.each(json.results.bindings, function(i, queryResult) {
            var url = queryResult.doc.value;
            $.ajax({
                type: 'get',
                url: url,
                dataType: 'text',
                success: function(title) {
                    // Do stuff with url and title here.
                }
            });
        });
    },
    error: function() {
        alert('fail');
    }
});

如果你确实需要等待所有人返回,它会变得有点复杂。您可以使用$.ajax() returns a promise这一事实,然后在所有这些承诺得到解决后使用$.when()执行代码。

$.ajax({
    url: queryUrlDoc,
    dataType: 'json',
    success: function(json) {
        var urls = [];

        var promises = $.map(json.results.bindings, function(queryResult) {
            var url = queryResult.doc.value;
            urls.push();
            return $.ajax({ type: 'get', url: url, dataType: 'text' });
        });

        $.when.apply($, promises).done(function() {
            var titles = (promises.length > 1)
                ? $.map(arguments, function(a) { return a[0]; })
                : [arguments[0]];

            var items = $.map(urls, function(url, i) {
                return { url: url, title: titles[i] };
            });

            // Do stuff with items array here.
        }).fail(function() {
            alert('fail');
        });
    },
    error: function() {
        alert("fail");
    }
});

有关如何根据传递给titles函数的回调的参数构造$.when(...).done()数组的信息,请参阅this Stackoverflow answer

上述代码的替代方法是使用$.Deferred()为ajax调用创建自己的promise,以便控制已解析的数据。

$.ajax({
    url: queryUrlDoc,
    dataType: 'json',
    success: function(json) {
        var promises = $.map(json.results.bindings, function(queryResult) {
            var url = queryResult.doc.value;
            return $.Deferred(function(deferred) {
                $.ajax({
                    type: 'get',
                    url: url,
                    dataType: 'text',
                    success: function(title) {
                        deferred.resolve({ url: url, title: title });
                    },
                    error: function(jqXHR, textStatus, errorThrown) {
                        deferred.reject([jqXHR, textStatus, errorThrown]);
                    }
                });
            }).promise();
        });

        $.when.apply($, promises).done(function() {
            var items = $.makeArray(arguments);

            // Do stuff with items array here.
        }).fail(function() {
            alert('fail');
        });
    },
    error: function() {
        alert('fail');
    }
});

答案 1 :(得分:1)

这里有2个问题:设计和异步。

首先,为什么需要对第一个AJAX请求返回的每个元素进行AJAX调用?如果第一个请求发送100个元素,那么你将同时执行100个AJAX调用,并且只是杀死你的浏览器,这并不好。我认为您应该尝试减少完成的AJAX请求量,并且可能在第一个AJAX请求中检索所有必需的信息。你做的越少,它就越好(对于浏览器,对于用户,对服务器,对你来说也是如此)。

其次,你有异步问题。 AJAX调用是异步的。因此,在您当前的代码中,您在获取任何元素之前都使用temp变量。看看这个,我已经简化了代码并添加了一些console.log语句:

$.ajax({
    dataType : "json",
    url : queryUrlDoc,
    success : function(json) {
        console.log('First AJAX call is finished');

        var queryResults = json.results.bindings;
        var temp = [];

        for(var i in queryResults)
        {
            var url = queryResults[i]['doc'].value;

            $.ajax({
                url: url,
                type: 'get',
                success: function(data) {
                    console.log('Second AJAX call is finished, with data: ' + data);

                    temp.push({
                      'url' : url,
                      'title': data
                    });

                    console.log('temp array now contains ' + temp.length + ' elements');
                }
             });
        }

        console.log('iterating over temp array, it contains ' + temp.length + ' elements');

        for(var i in temp)
        {
            uri = temp[i]['url'];
        }

    }
});

你能猜出你会得到什么输出?我打赌你会得到这样的东西:

First AJAX call is finished
iterating over temp array, it contains 0 elements
Second AJAX call is finished, with data: <data from first subrequest>
temp array now contains 1 elements
Second AJAX call is finished, with data: <data from second subrequest>
temp array now contains 2 elements

看看发生了什么? for循环在<{strong> {/ 1}}回调之前执行,因为AJAX调用是异步的。为了做你想做的事,你应该使用像Promises这样的东西(参见John的答案以获得更多解释)。

答案 2 :(得分:0)

尝试使用while,类似的内容会在上一次成功之后发送下一个请求:

var next = false;
var i = 0;

while(next){
    next = false;

    var url = queryResults[i]['doc'].value;

    $.ajax({
        url: url,
        type: 'get',
        success: function(data) {

            title = data;
            var item = {
                'url' : url,
                'title': title
            };
            temp.push(item);

            next=true;
            i++;
        } 
    });
}

希望这有帮助。

答案 3 :(得分:0)

在调用多个相关的AJAX调用时,你应该使用jQuery promises。

jQuery.when()

jQuery deferred

以下是一个例子:

var firstPromise = $.ajax("http://example.com/first");
var secondPromise = $.ajax("http://example.com/second");

$.when(firstPromise, secondPromise).done(function(firstData, secondData) {
  // do something
});