等待ajax请求中的代码完成后再做一些事情

时间:2014-08-25 18:43:15

标签: jquery ajax jquery-deferred

我有以下代码:

var requestEvents = getEvents();

requestEvents.done(function (resp1) {

    $(resp1).find('events').each(function() {
        var event_id = $(this).find('id').text();
        var event_name = $(this).find('name').text();
        var event_description = $(this).find('description').text();
        var event_start_date = $(this).find('startDate').text();
        var event_end_date = $(this).find('endDate').text();

        count++;
        if (count >= 2) {
            // This will execute after the first request is done
            var requestParticipants = getParticipants(event_id);
            var requestPlaces = getPlaces(event_id);
            var requestMedia = getMedia(event_id);

            $.when(requestParticipants, requestPlaces, requestMedia).done(function (resp2, resp3, resp4) {
                participants.push(resp2[2].responseText);
                media.push(resp3[2].responseText);
                places.push(resp4[2].responseText);

                var new_event = {
                    'id' : event_id,
                    'name' : event_name,
                    'description' : event_description,
                    'start_date' : event_start_date,
                    'end_date' : event_end_date,
                    'participants' : participants,
                    'pictures' : media,
                    'places' : places
                };
                events.push(new_event);

                console.log(resp2[2].responseText);
                console.log(resp3[2].responseText);
                console.log(resp4[2].responseText);
            });
        }
    });
});

一切都按预期工作,但是当.done中的代码完成后,我需要执行更多代码。

我试过

.then( function(){

});

但这会在所有事件都放入数组之前运行。

我需要等待所有事件放在事件数组中的东西,这个事件现在还没有发生。我怎样才能做到这一点?

ajax调用方法:

function getEvents(){
    return $.ajax({
        type:"GET",
        url: "http://"+server+":"+port+"/remember-me/rest/events?user="+ user,
        dataType : "xml"
    });
}

function getParticipants(event_id){
    return $.ajax({
        type:"GET",
        url: "http://"+server+":"+port+"/remember-me/rest/events/"
        + event_id + "/participants",
        dataType : "xml"
    });
}

function getMedia(event_id){
    return $.ajax({
        type:"GET", 
        url: "http://"+server+":"+port+"/remember-me/rest/events/"
        + event_id+ "/media",
        dataType : "xml"
    });
}

function getPlaces(event_id){
    return $.ajax({
        type:"GET", 
        url: "http://"+server+":"+port+"/remember-me/rest/events/"
        + event_id+ "/places",
        dataType : "xml"
    });
}

3 个答案:

答案 0 :(得分:3)

最简单的方法?所有操作完成后,使用$.Deferred生成您自己的延迟对象(终结器)和resolve。基本上是:

var requestEvents = getEvents();
var finalizer = $.Deferred(); // ADDED

requestEvents.done(function (resp1) {
    var unfinishedEvents = $(resp1).find('events').length; // ADDED

    $(resp1).find('events').each(function() {
        /* ... */

        count++;
        if (count >= 2) {
            // This will execute after the first request is done
            var requestParticipants = getParticipants(event_id);
            var requestPlaces = getPlaces(event_id);
            var requestMedia = getMedia(event_id);

            $.when(requestParticipants, requestPlaces, requestMedia).done(function (resp2, resp3, resp4) {
                /* ... */
            })
            .then(function(){                 // ADDED
                if (--unfinishedEvents == 0){ // ADDED
                    finalizer.resolve();      // ADDED
                }                             // ADDED
            });                               // ADDED
        }
    });
});

finalizer.done(function(){    // ADDED
  /* ... */                   // ADDED
});                           // ADDED

示例可以在这里找到:http://jsfiddle.net/j8o2y88z/3/(观察控制台)。要查看它随机化了多少事件,请参阅http://jsfiddle.net/j8o2y88z/4/

答案 1 :(得分:1)

编辑,使用单个函数定义单个$.ajax()请求的方法;将请求设置存储在单个阵列中。 url或其他参数(例如data)传递给request函数。利用.each()的范围循环遍历设置数组,将数据推送到events数组。当events数组length等于设置lengthrequests(jsfiddle urlslength时,请使用.always()回调执行其他任务。

尝试

..
            $.when(requestParticipants, requestPlaces, requestMedia)
            .done(function (resp2, resp3, resp4) {
                participants.push(resp2[2].responseText);
                media.push(resp3[2].responseText);
                places.push(resp4[2].responseText);

                var new_event = {
                    'id' : event_id,
                    'name' : event_name,
                    'description' : event_description,
                    'start_date' : event_start_date,
                    'end_date' : event_end_date,
                    'participants' : participants,
                    'pictures' : media,
                    'places' : places
                };
                events.push(new_event);

                console.log(resp2[2].responseText);
                console.log(resp3[2].responseText);
                console.log(resp4[2].responseText);
            })
            // `always` , or `complete` callback 
            // i.e.g., `10` : actual or expected `events` array` `.length` 
            .always(function() {
              if (events.length === 10) {
                // do stuff
                // when `events` `.length` === total requests 
                console.log(events.length);
              };

            })
..

jsfiddle http://jsfiddle.net/guest271314/z66otnc6/

答案 2 :(得分:0)

如果布莱恩·克里斯蒂的回答是正确的,那么以下简化也将是正确的......并且显得更加优雅。

首先是一些目标:

  • 避免使用外部数组来累积结果
  • 避免创建和解析明确的$.Deferred()
  • 避免需要手动递减unfinishedEvents
  • 避免需要手动递增count
  • 减少"流量控制"代码
  • 清除不必要的任务。

这里是以骨架形式的流量控制:

getEvents().then(function (resp1) {
    return $.when.apply(null, jQueryCollection.map(function(item, i) {
        ...
        return (i < 2) ? null : $.when(p0, p1, p2).then(function(a0, a1, a2) {
            return {...};
        });
    }).get());
});

注意:

  • 在两个位置用.done()替换.then()并进行适当的返回,允许渐进式过滤。 .done()是一种死胡同的方法,虽然它本身具有功能,却不会对承诺链做出贡献
  • .get()是必要的,因为jQueryCollection.map()会返回另一个jQueryCollection。

完整的代码仍然相当简洁:

var promiseOfEvents = getEvents().then(function (resp1) {
    return $.when.apply(null, $(resp1).find('events').map(function (event, i) {
        var $event = $(event),
            event_id = $event.find('id').text();
        return (i < 2) ? null : $.when(getParticipants(event_id), getPlaces(event_id), getMedia(event_id)).then(function (a0, a1, a2) {
            return {
                'id' : event_id,
                'name' : $event.find('name').text(),
                'description' : $event.find('description').text(),
                'start_date' : $event.find('startDate').text(),
                'end_date' : $event.find('endDate').text(),
                'participant' : a0[2].responseText,
                'picture' : a1[2].responseText,
                'place' : a2[2].responseText
            };
        });
    }).get());
});

promiseOfEvents.then(function () {
    // now compose `events` from the arguments
    var events = [].slice.apply(arguments);
    // work with `events` here
});

注意:

  • 永远不需要外部成员events。即使使用原始代码,所需的数据也可以(并且应该)通过承诺链提供
  • 外部成员participantsmediaplaces从来都不是必需的。即使使用原始代码,单个数据项也可以(并且应该)作为events的属性包含在内,而不使用外部数组。