Javascript Возвращает сумму петли
Я запускаю последовательность из 3 записей ajax, и в конце мне нужно суммировать устройства из цикла while внутри каждого цикла. Сначала я получаю идентификатор сеанса, затем я получаю количество устройств и выполняю цикл foreach, чтобы получить идентификаторы каждого устройства. После этого я делаю цикл 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");
}
*/
});
1 ответ
$.post
вы делаете для каждого устройства потребления в месяц в while
Цикл является асинхронным, и поэтому выполнение кода продолжается вплоть до той части печати, где вы получаете 0. Если вы зарегистрируете значение на консоли после всех публикаций, вы увидите, что результат рассчитан правильно. Чтобы увидеть это в вашем примере, удалите все console.log
звонки и заменить линию total += val.value;
с функцией, которая добавляет к глобальному значению и регистрирует новое значение в консоли, например:
function addToTotal(value) {
total += value;
console.log(total);
}
...
/* Sum each month consumption value */
if(val.value !== '') {
addToTotal(val.value);
}
...
Чтобы определить, когда все сообщения завершены, а затем рассчитать общую сумму, вы можете использовать обещания jQuery, так как метод $.post уже возвращает их. Посмотрите на 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 */);