将jQuery Deferred与包含$ .each的多个ajax一起使用

时间:2018-06-19 17:45:11

标签: javascript jquery jquery-deferred

我正在尝试为以下情况创建一个javascript对象

一项调查采访了多个人有关他们在多餐中食用的食物的信息。该对象需要嵌套如下:-

case={}
case[x].Interview={}
case[x].Interview[y].meals={}
case[x].Interview[y].meals[z].Food=[]

我通过以下代码实现了这一目标

var $caseoffset=0
loadcases()
function loadcases() {
    $.ajax({
        url: "functions.php",data: {offset: $caseoffset,method: "getCase"},method: "post",dataType: 'json',
        success: function(result) {
            cases = result;
            loadinterview(cases[$caseoffset].fldCaseID)         
        }
    })  
}

function loadinterview($CaseID) {
    $.ajax({
        url: "functions.php",
        data: {method: "getinterview",caseid: $CaseID}, method: "post",dataType: 'json',
        success: function(result) {
            thiscase=cases[$caseoffset]
            thiscase.interviewcount=result.length
            thiscase.interviews={}

            $.each(result,function(key,val){
                thiscase.interviews[val.fldInterviewID]=val
                loadmeals(val.fldInterviewID)
            })  
        }    
    })
}
function loadmeals($InterviewID) {
    $.ajax({
        url: "functions.php",
        data: {method: "getmeal",InterviewID: $InterviewID},method: "post",dataType: 'json',
        success: function(result) {
            thiscase.interviews[parseInt($InterviewID)].mealcount = result.length
            thiscase.interviews[parseInt($InterviewID)].meals={}

            $.each(result, function(key, val) {

                thiscase.interviews[parseInt($InterviewID)].meals[parseInt(val.fldMealHistoryID)] = val
                getfoodinmeal($InterviewID, val.fldMealHistoryID)
            })
        }
    })
}

function getfoodinmeal($interviewid, $mealid) {
    $.ajax({
        url: "functions.php",data: {method: "getfoodinmeal",mealid: $mealid},
        method: "post",

        dataType: 'json',

        success: function(result){
            foodinmeal = [];

            $.each(result, function(key, val) {
                foodinmeal.push(val.fldFoodID)
            })

            thiscase.interviews[$interviewid].meals[$mealid].food = foodinmeal

        }
    })
}

问题是,每位访调员消耗的所有食物都整理好之后,我想进行一些计算。如何创建延期声明以解决该问题。

4 个答案:

答案 0 :(得分:6)

从jQuery 1.5开始,$.ajax()返回实现Promise接口的jqXHR

这意味着您可以将其与Promise.all()https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all)组合使用

类似的事情应该起作用:

Promise.all([
    $.ajax({
        url: "a.php"
    }),
    $.ajax({
        url: "b.php"
    }),
    $.ajax({
        url: "c.php"
    }),
]).then(function() {
    // the 3 $ajax() call are finished
})

答案 1 :(得分:2)

以上所有答案都很不错,可以解决您的问题。但是调用多个ajax调用会损害网站的性能。如果您不使用第三方API,并且可以控制API,则应更改API并使其更加灵活。 API的设计方式应使您可以使用许多参数查询它,并且它将在单个请求中返回结果。例如。在上述情况下,您可以在单个请求中传递所有ID,并获取所有ID的数据。或者在最佳情况下,您只是要求情况,它将返回您需要的所有信息(面试,用餐和食物)。 API将负责以您需要的形式查询数据。

答案 2 :(得分:1)

使用promises从中间步骤中返回值,并使用Promise.all来组合它们:

function loadcase(offset) {
    return $.ajax({
        url: "functions.php",
        data: {method: "getCase", offset: offset},
        method: "post", dataType: 'json',
    }).then(function(cases) {
        return loadinterview(cases[$caseoffset]);
    })
}

function loadinterview(thiscase) {
    $.ajax({
        url: "functions.php",
        data: {method: "getinterview", caseid: thiscase.fldCaseID},
        method: "post", dataType: 'json'
    }).then(function(result) {
        thiscase.interviewcount=result.length
        thiscase.interviews={}

        var promises = $.map(result,function(key,val){
            thiscase.interviews[val.fldInterviewID]=val
            return loadmeals(val);
        })

        return Promise.all(promises).then(function() {
            return thiscase;
        });
    });
}
function loadmeals(thisinterview) {
    $.ajax({
        url: "functions.php",
        data: {method: "getmeal", InterviewID: thisinterview.fldInterviewID},
        method: "post", dataType: 'json'
    }).then(function(result) {
        thisinterview.mealcount = result.length
        thisinterview.meals={}

        var promises = $.map(result, function(key, val) {
            thisinterview.meals[val.fldMealHistoryID] = val
            return getfoodinmeal(val);
        })
        return Promise.all(promises).then(function() {
            return thisinterview;
        });
    })
}

function getfoodinmeal(thismeal) {
    $.ajax({
        url: "functions.php",
        data: {method: "getfoodinmeal", mealid: thismeal.fldMealHistoryID},
        method: "post", dataType: 'json',
    }).then(function(result) {
        thismeal.food = $.map(result, function(key, val) {
            return val.fldFoodID;
        })l
        return thismeal;
    })
}

loadcase(0).then(function(case) {
    // everything is loaded
    console.log(case);
})

答案 3 :(得分:0)

这两个答案都不错,但问题是Promise接口仅在ES6中可用。有两种可能的情况。

  1. 使用polyfill-> https://www.npmjs.com/package/promise-polyfill
  2. 使用jQuery.when()。假设您创建了一个对getfoodinmeal的所有请求保证的数组。然后,您需要等待所有这些,因此请使用此格式$.when.apply($.when, promises).then(/* all food is now loaded*/);。我使用了两次,效果很好。我更喜欢这种方式,因为我不需要加载其他代码。