如何在Nodejs

时间:2018-04-19 15:59:42

标签: node.js express asynchronous promise

我试图在所有承诺都已解决时返回数据,但不知何故,代码在承诺解析之前执行。

这是我尝试但没有运气的代码。

     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;
    });


});

此外,这是返回此类复杂数据的正确方法吗?

1 个答案:

答案 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()
  • 分别为“new”和“used”映射lastweekDates;将两者挤压成一个.map()只会使问题复杂化
  • 有一个“master”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
                };
            });
        }));
    });
};