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

Using jQuery Deferred with multiple ajax containing $.each

我正在尝试为以下场景创建一个 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

        }
    })
}

问题是我想在每个面试官消耗的所有食物都被编译后进行一些计算。我如何创建延迟语句来解决这个问题。

自 jQuery 1.5 $.ajax() returns jqXHR 实现 Promise 接口。

这意味着您可以将它与 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
})

对中间步骤中的 return 值使用承诺,并使用 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);
})

这里的两个答案都很好,但问题是 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*/);。我用了两次,效果很好。我更喜欢这种方式,因为我不需要加载额外的代码。

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