我需要从后端收集不同设备的日志,然后将其导出到csv文件。问题是设备的数量可能会有所不同。所以我向后端询问设备数量并循环查看日志请求。
问题是for...
循环的运行速度比我获得$.post
的响应速度快得多,所以在得到响应之前循环结束。经过一些研究,我可以处理这种行为,但现在我被要求将数据添加到请求中,对此我没有存储相应设备的参考。所以我在外部js文件中添加了我需要轮询的设备名称和点,所以我有一个定义的列表可以循环。
我尝试使用for循环的索引来获取设备名称,这不起作用,因为循环太快了。现在我已经创建了一个解决方法,通过定义计数器并将设备推送到另一个变量中。这不会感觉“干净”,应该有更好的方法来轮询数据并跟踪它是哪个设备。
到目前为止的代码:
function collectData() {
var outString = "";
var lots of stuff I can pre-fetch
var logs = function (outString, saveCSV) {
var postString;
var devices = [];
var count = 0;
for (i = 1; i <= maxDevice; i++) {
postString = build postString in loop
devices.push(spots[0][i - 1]);
$.post('/path/foobar.db',
postString,
function (data) {
outString += "Spotlist for: " + spots[0][count] + "\n";
count++;
outString += data.replace(/{/g, "").replace(/}/g, "").replace(/:/g, ";").replace(/,/g, "\n").replace(/\"/g, "");
outString += "\n\n";
});
postString = "/path/eventlog.csv?device=" + i;
$.get(postString,
function (data) {
outString += "Event Log: \n" + data + "\n";
});
postString = "/path/errorlog.csv?device=" + i;
$.get(postString,
function (data) {
outString += "Error Log: \n" + data + "\n";
});
}
$(document).ajaxStop(function () {
saveCSV(outString, filename);
$(this).unbind('ajaxStop');
});
};
var saveCSV = function (outString, filename) {
var tempString = "data:text/csv;charset=utf-8," + outString;
var encodedUri = encodeURI(tempString);
var a = document.getElementById("dlLink");
if (window.navigator.msSaveOrOpenBlob) {
blobObject = new Blob([outString], {type: 'text/csv;charset=utf-8'});
window.navigator.msSaveBlob(blobObject, filename);
} else
{
a.setAttribute("href", encodedUri);
a.setAttribute("download", filename);
a.click();
}
};
outString = lots of predefined and pre-fetched stuff
outString += "Device data: \n\n";
logs(outString, saveCSV);
}
我不满意的部分是:
for (i = 1; i <= maxDevice; i++) {
postString = "get = {" + i + ":en:[";
for (j = 0; j < spots[i].length; j++) {
postString += '"' + spots[i][j] + '",';
}
postString = postString.slice(0, -1) + "]}";
devices.push(spots[0][i - 1]);
$.post('/path/foobar.db',
postString,
function (data) {
outString += "Spotlist for: " + spots[0][count] + "\n";
count++;
outString += data.replace(/{/g, "").replace(/}/g, "").replace(/:/g, ";").replace(/,/g, "\n").replace(/\"/g, "");
outString += "\n\n";
});
要输出我收集的设备,我使用计数器来跟踪设备名称。我有预感这不是最好和“最干净”的方法,所以我想问一下,在收集制作帖子的正确设备方面是否有更好的方法来处理异步(sp?)如果一切都已完成,还要触发DL。
由于我的问题似乎并不清楚,或许我需要缩小范围。代码有效,但似乎只是被我修改,应该有更清洁的方法来
A)处理posts / gets,因为CSV的字符串只是按照请求被回答的方式放在一起,所以设备1不是csv中的第一个,而是第一个。 $(document).ajaxStop
等待完成所有事情,但不能以正确的顺序完成。
B)我需要将for循环的索引与我为数据轮询的设备相关联。我使用了额外的变量,我想要通过一个额外的数组。还有更好的办法吗?
答案 0 :(得分:2)
问题是你需要按顺序运行在获得对AJAX调用的响应后调用的方法。
要做到这一点,你必须承诺所有jQuery AJAX调用都会返回promises。您可以执行以下操作,而不是将代码作为参数传递:
var functionToRunAfterResponse(params) = function(params) {
// do something with params
};
var promise = $.post(/*...*/); // some kind of ajax call
promise.then(functionToRunAfterResponse);
请注意,functionToRunAfterResponse
将接收响应数据作为参数。即它相当于:
promise.then(function(reponseData) {
functionToRunAfterResponse(responseData);
});
这是一个简单的通话方式。请参阅$.then和deferred以及promise文档。
如果你要打一堆电话,你必须做以下事情:
promise.then
以获得所需的结果。为此,您可以使用$.when。
代码结构应该是这样的(伪代码):
var promises = [];
// Make the calls, and store the promises
for(/**/) {
promises.push( $.post or some other kind of ajax call );
}
// Ensure that all the responses have arrived
$.when.apply($, promises) // See below note
.then(function() {
for each promise in promises
promise[i].then(function(reponseData) {
// run the necessary code
});
注意:Here you've got a deeper explanation,但基本上,由于$.when
需要一系列承诺,例如:$.when(promise1, promise2, ...)
并且您有一个数组promises[]
,您必须使用申请进行调用,以便数组中的项目作为单独的参数传递。
最终说明:
1)考虑到AJAX调用可能会失败。在这种情况下,您将获得失败的承诺,而不是已解决的承诺。你应该检查一下。如果任何承诺失败,$.when
将无法按预期运行:
方法[when]将在所有Deferred解决后立即解析其主延期,或者在其中一个Deferred被拒绝后立即拒绝主延期。
2)为了处理错误,then
有两个参数:
$.when.apply().then(function() { /* success */ }, function() { /* error */ });
3)当你按照我的解释进行呼叫时,它们都是并行执行的,并且响应将以任何顺序到达。即不保证您将按照拨打电话的顺序收到所有回复。他们甚至可能会失败,正如我在1)中所解释的那样,这就是为什么你必须使用when
并再按顺序运行
4)使用异步方法很棒,但是你有责任检查它们是否没有失败,并按正确的顺序运行你得到响应后需要运行的代码。
答案 1 :(得分:0)
我无法理解你的问题,但主要问题是异步,对吧?
尝试异步调用函数(摘要版本):
// Function that manage the data from ajax
var myResponseFunction = function (data) {
$('#response').html('data: ' + JSON.stringify(data));
};
// Ajax function, like your post with one parameter (add all you need)
function myAJAXFunction(callback) {
$.ajax({
type: 'POST',
url: '/echo/json/',
dataType: 'json',
data: {
json: JSON.stringify({
'foo': 'bar'
})
}
}).done(function(response) {
// Done!! Now is time to manage the answer
callback(response);
}).fail(function (jqXHR, textStatus, errorThrown) {
window.console.error('Error ' + textStatus + ': ' + errorThrown);
});
}
// Usually, this function it's inside "document.ready()".
// To avoid the ajax problem we call the function and "data manage function" as parameter.
for (i = 1; i <= maxDevice; i++) {
myAJAXFunction(myResponseFunction);
}
https://jsfiddle.net/erknrio/my1jLfLr/
这个例子是西班牙语,但在这个答案中,您的代码用英语注释:)。
对不起我的英文:S。