我试图在所有承诺都已解决时返回数据,但不知何故,代码在承诺解析之前执行。
这是我尝试但没有运气的代码。
let promises = [];
return this.getAutoDealerByAutoGroupID(1).then(function (autoDealers) {
//Iterate on dealers --- Map = foreach
let i = 0;
return autoDealers.map(function (dealer) {
i++;
let dealerObj = {
sales: {
new: [],
used: [],
},
vehicleModel: {
new: [],
used: [],
}
};
autoDealerID = dealer.id;
dealerObj.dealer = dealer;
//Iterate on dates
//Last Week sales
lastweekDates.map((saleDate) => {
salesFilter.saleDate = saleDate;
salesFilter.autoDealerID = autoDealerID;
salesFilter.vehicleTypes = ['New'];
let sumSales = saleRepository.sumSales(salesWhere, salesFilter).then(function (resultSumSales) {
let resultParseData = JSON.parse(JSON.stringify(resultSumSales));
resultParseData = baseService.makeNullKeysToZero(resultParseData);
resultParseData[0].sale_date = saleDate;
dealerObj.sales.new.push(resultParseData[0]);
});
salesFilter.vehicleTypes = ['Used'];
let sumSalesUsed = saleRepository.sumSales(salesWhere, salesFilter).then(function (resultSumSales) {
let resultParseData = JSON.parse(JSON.stringify(resultSumSales));
resultParseData = baseService.makeNullKeysToZero(resultParseData);
resultParseData[0].sale_date = saleDate;
dealerObj.sales.used.push(resultParseData[0]);
});
promises.push(sumSales);
promises.push(sumSalesUsed);
});
});
//Loop End
return Promise.all(promises).then(function (result) {
return dealersData;
});
});
此外,这是返回此类复杂数据的正确方法吗?
答案 0 :(得分:2)
我需要在包含嵌套循环的所有循环结束时返回数据但不知何故最后promise.all在所有上述脚本执行之前执行。
如果您获得正确的整体模式,那么自然会发生所需的数据。
考虑一下:
function foo(arr) {
return doSomethingAsync().then(function(result) {
return Promise.all(arr.map(function (item) {
return doSomethingElseAsync(result, item);
}));
});
}
foo()
会返回一个承诺,该承诺会传递一系列源自doSomethingElseAsync()
的结果。
从本质上讲,这就是你要做的一切。你的整体模式不需要那么复杂。
此外,这是返回此类复杂数据的正确方法吗?
不是出于多种原因,主要是因为您期望外部数组promises
过多。就目前而言,数组在外部集合和内部承诺集之间“共享”,这是一种混乱的方法。
您希望实现的真正复杂性在于收集经销商数据,这涉及多个异步函数调用。参考上面的模式,这意味着你的最里面的函数将是更多的行,你应该在其中:
.map()
来创建承诺数组,每个承诺都有自己的Promise.all()
。lastweekDates
;将两者挤压成一个.map()
只会使问题复杂化Promise.all()
来聚合各种异步组件dealerObj
以传递(最终)所需的数组。这里的模式稍微充实,以显示所需的内部模式:
exports.getData = function (autoGroupId, startDate, endDate, givenDate) {
return this.getAutoDealerByAutoGroupID(1)
.then(function (autoDealers) {
return Promise.all(autoDealers.map(function (dealer) {
let newSalesPromise = Promise.all(lastweekDates.map(saleDate => {
return saleRepository.sumSales(...) // with "new" parameter
.then(...);
}));
let usedSalesPromise = Promise.all(lastweekDates.map(saleDate => {
return saleRepository.sumSales(...) // with "used" parameter
.then(...);
}));
let newVehicleModelsPromise = vehicleRepository.getVehicleModels(...)
.then(vehicles => {
return Promise.all(vehicles.map(function (vehicle) {
return saleRepository.countSales(...)
.then(...);
}));
});
// this appears to be identical for all dealers, therefore could be moved outside autoDealers.map()
let workingDaysPromise = workingDayRepository.getFilteredWorkingDays(workingDaysFilter)
.then(...);
// Here, use `Promise.all()` again to aggregate the individual data-delivering promises and create the desired dealerObj object
return Promise.all([newSalesPromise, usedSalesPromise, newVehicleModelsPromise, workingDaysPromise])
.then(function ([newSales, usedSales, newVehicleModels, workingDays]) { // deconstruct
// construct and return the `dealerObj` object
return {
'dealer': dealer,
'sales': { 'new': newSales, 'used': usedSales },
'vehicleModel': { 'new': newVehicleModels, 'used': [] }, // where does 'used' data come form?
'workingDays': workingDays
};
});
}));
});
}
现在,您可以在每个...
重新注入原始代码(或类似代码)。您应该(在我怀疑的某些调试之后)有一个将返回Promise<Array<dealerobjects>>
的函数。
请注意,.push()
的需求完全消失,有利于从.then()
回调中返回数据。
编辑:
基于......
workingDayRepository.getFilteredWorkingDays(workingDaysFilter)
总是会给出相同的结果,this.getAutoDealerByAutoGroupID(1)
和workingDayRepository.getFilteredWorkingDays(workingDaysFilter)
可以并行执行(这似乎是合理的) ...然后workingDayRepository.getFilteredWorkingDays(workingDaysFilter)
可以在模式的轻微修改版本中预先执行一次,如下所示:
exports.getData = function (autoGroupId, startDate, endDate, givenDate) {
return this.getAutoDealerByAutoGroupID(1)
.then(function (autoDealers) {
let workingDaysPromise = workingDayRepository.getFilteredWorkingDays(workingDaysFilter)
.then(...); // (moved)
return Promise.all(autoDealers.map(function (dealer) {
let newSalesPromise = Promise.all(lastweekDates.map(saleDate => {
return saleRepository.sumSales(...) // with "new" parameter
.then(...);
}));
let usedSalesPromise = Promise.all(lastweekDates.map(saleDate => {
return saleRepository.sumSales(...) // with "used" parameter
.then(...);
}));
let newVehicleModelsPromise = vehicleRepository.getVehicleModels(...)
.then(vehicles => {
return Promise.all(vehicles.map(function (vehicle) {
return saleRepository.countSales(...)
.then(...);
}));
});
// Here, use `Promise.all()` again to aggregate the individual data-delivering promises and create the desired dealerObj object
return Promise.all([newSalesPromise, usedSalesPromise, newVehicleModelsPromise, workingDaysPromise])
.then(function ([newSales, usedSales, newVehicleModels, workingDays]) {
// construct and return the `dealerObj` object
return {
'dealer': dealer,
'sales': { 'new': newSales, 'used': usedSales },
'vehicleModel': { 'new': newVehicleModels, 'used': [] }, // where does 'used' data come form?
'workingDays': workingDays
};
});
}));
});
};