Javascript Return 循环求和

Javascript Return loop sum

我是 运行 3 个 ajax 帖子的序列,最后我需要从每个循环内的 while 循环中总结设备。首先我获得会话 ID,然后我获得设备数量并执行 foreach 循环以获取每个设备的 ID。之后我做了一个 while 循环,从开始日期到今天日期每月增加,并获得设备月总消耗量和总和。我需要所有设备月耗电量的总和。

我在函数中间做了评论,在那里我可以求和,在那里我得到值 0。我什至尝试运行一个单独的函数,它在最后一个评论中,但它一直返回未定义。

希望大家能看懂。

var SESSION_ID ='';
var total = parseFloat(0.0);
$.post("http://xxx.xxxxxxxx.com/users/auth", {
    token : "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    }, function (session) {
        if(session) {
            console.log("Session id received.");
            SESSION_ID = session.id;
            console.log("Looking for devices.");
            $.post("http://xxx.xxxxxxxxxxxxxxx.com/devices/list", {
                id : session.id
            }, function (devices) {
                if(devices) {

                    /* Loop trough devices to get id of each device */
                    $.each(devices, function(index, val) {

                         /* Set start date */
                        var targetDate = new Date();
                        targetDate.setFullYear(2015);
                        targetDate.setMonth(2);
                        targetDate.setDate(1);
                        targetDate.setHours(0);
                        targetDate.setMinutes(0);
                        targetDate.setSeconds(0);
                        var currentDate = new Date();

                        /* Increase 1 month until current date */
                        while (targetDate.getMonth() !== currentDate.getMonth() || targetDate.getFullYear() !== currentDate.getFullYear()) {
                            //console.log("Month: " + (targetDate.getMonth() + 1) + "; Year: " + targetDate.getFullYear());
                            var month = targetDate.getMonth() + 1,
                                year = targetDate.getFullYear();

                            $.post("http://xxx.xxxxxxxxxxxxxx.com/devices/" + val.id + "/consumptions?year=" + year + "&month=" + month + "&resolution=month", {
                                id : SESSION_ID
                            }, function (consumptions) {
                                if(consumptions) {
                                    $.each(consumptions, function(index, val) {
                                         /* Sum each month consumption value */
                                         if(val.value !== '') {
                                            total += val.value;
                                         }
                                    });

                                    // Return values float values Eg.: 11774.86060142517 and keeps
                                    console.log(total);
                                }
                            }, "json");
                            // Increase month
                            targetDate.setMonth(targetDate.getMonth() + 1);

                            // console.log(total) returns 0
                            console.log(total);
                        }
                    });

                    // Total returning 0
                    // console.log(total);
                } else {
                    console.log("No devices found.");
                }
            }, "json");
        } else {
            console.log("No session id");
        }
    }, "json");

    /*
    function getMonthConsumption(device_id, device_year, device_month) {
        $.post("http://xxx.xxxxxxxxxxxxxx.com/devices/" + device_id + "/consumptions?year=" + device_year + "&month=" + device_month + "&resolution=month", {
            id : SESSION_ID
        }, function (consumptions) {
            if(consumptions) {
                $.each(consumptions, function(index, val) {

                     if(val.value !== '') {
                        total = total + val.value;
                     }
                });
                return consumptions;
            }
        }, "json");
    }
    */
});

您在 while 循环中为每个月的每个设备消耗所做的 $.post 是异步的,因此代码执行将继续到您获得 0 的打印部分。如果您记录该值在所有 post 之后到控制台,您将看到结果已正确计算。要在您的示例中看到这一点,请删除所有 console.log 调用并将行 total += val.value; 替换为添加到全局值并在控制台中记录新值的函数,例如:

function addToTotal(value) {
  total += value;
  console.log(total);
}

...
/* Sum each month consumption value */
if(val.value !== '') {
  addToTotal(val.value);
}
...

要检测所有 post 何时完成,然后计算总和,您可以使用 jQuery 承诺,因为 $.post 方法已经 returns 一个。看看 jQuery.when()

编辑

根据此处的评论,提出了一个具有 jQuery 承诺的解决方案。 首先添加一组承诺,您将在其中保留所有消费请求,然后收集所有响应并处理它们:

var SESSION_ID ='';
var total = parseFloat(0.0);

$.post("http://xxx.xxxxxxxx.com/users/auth", {
    token : "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    }, function (session) {
        if(session) {
            console.log("Session id received.");
            SESSION_ID = session.id;
            console.log("Looking for devices.");
            $.post("http://xxx.xxxxxxxxxxxxxxx.com/devices/list", {
                id : session.id
            }, function (devices) {
                if(devices) {

                    var promises = [];

                    /* Loop trough devices to get id of each device */
                    $.each(devices, function(index, val) {

                         /* Set start date */
                        var targetDate = new Date();
                        targetDate.setFullYear(2015);
                        targetDate.setMonth(2);
                        targetDate.setDate(1);
                        targetDate.setHours(0);
                        targetDate.setMinutes(0);
                        targetDate.setSeconds(0);
                        var currentDate = new Date();

                        /* Increase 1 month until current date */
                        while (targetDate.getMonth() !== currentDate.getMonth() || targetDate.getFullYear() !== currentDate.getFullYear()) {
                            //console.log("Month: " + (targetDate.getMonth() + 1) + "; Year: " + targetDate.getFullYear());
                            var month = targetDate.getMonth() + 1,
                                year = targetDate.getFullYear();

                            var postPromise = $.post("http://xxx.xxxxxxxxxxxxxx.com/devices/" + val.id + "/consumptions?year=" + year + "&month=" + month + "&resolution=month", {
                                id : SESSION_ID
                            }, "json");
                            promises.push(postPromise);

                            // Increase month
                            targetDate.setMonth(targetDate.getMonth() + 1);
                        }
                    });

                    // Gather all responses
                    $.when.apply($, promises).then(function() {
                        var total = 0;
                        // Here arguments will have the responses from all $.post requests added to the promises array. The actual respo
                        $.each(arguments, function(index, jqueryPostResponses) {

                            var consumptions = jqueryPostResponses[0] // first object is the data;

                            $.each(consumptions, function(index, val) {
                                /* Sum each month consumption value */
                                if(val.value !== '') {
                                    total += val.value;
                                }
                            });

                        });

                        return total;
                    }).then(doSomethingWithTotal);

                } else {
                    console.log("No devices found.");
                }
            }, "json");
        } else {
            console.log("No session id");
        }
    }, "json");

    function doSomethingWithTotal(totalSum) {
        $('#totalSum').text(totalSum);
    }
});

由于我无法在不知道实际响应的情况下测试此代码,您可能需要调整代码以使其正常工作。这是一个有效的 JSFiddle 来帮助你。

对于循环执行,将设备的 $.post 包装在一个新函数中,该函数将 运行 和 setInterval(theNewFunction, 1000 /* repeat interval in ms */);