我需要使用通过一系列AJAX检索的记录来填充HTML表 要求。 AJAX请求都是在while循环中生成的。发出的请求总数由服务器在先前的信息交换中提供的值控制。需要异步处理AJAX请求,同时需要按照最初请求的顺序处理请求的结果。
问题当然是对请求的响应并不总是如此 得到顺序回答。所以,在阅读了jquery的Deferred / promise接口后,我认为我手头有一个解决方案。但是对于我的生活,我无法理解如何推迟处理(填充表格)请求结果,直到先前请求的结果被处理为止。我在StackOverflow上发现了很多让我靠近的例子,但我似乎无法将这些点连接到我的应用程序中。
首先我尝试使用Deferred对象数组,认为我可以使用对它们的索引引用来处理一组记录,这取决于前一组处理的完成(在"按照要求& #34; order)数据集。但我无法弄清楚如何创建与实际数据处理相关的promise / Deferred对象 - 使用.then()。
var deferreds = [];
var recsPerPkt = 20;
var recRqstd = 0;
while(recsRqstd < totalRecsAvailable) {
console.log("Next record index to request: " + nextNdxRqst)
// Collect an array of the "promise" objects that $.ajax() returns for each call.
deferreds.push( $.ajax({
url: 'eventSummaryData',
type: 'get',
cache: false,
data: {StartNdxNum: nextNdxRqst, NumRecords: recsPerPkt}
}) // End $.ajax({ url: 'trainSummaryData', ...
); // End deferreds.push()
recsRqstd += recsPerPkt;
nextNdxRqst = recsRqstd;
if (deferreds.length > 1)
{
deferreds[deferreds.length - 2].then(
function (jsonData) {
if (jsonData.ok) {
// Now display the rows/records included in this packet.
displayrRecordsInTable({"rows": jsonData.rows});
}
},
function(){
$('#error-msg').text('HTTP error: ' + errorThrown);
}
);
}
}
$.when.apply(null, deferreds).then( function(){
console.log("Processing of AJAX'd data complete. ")
configureTableControls();
});
然后我发现了&#34;模式&#34;使用then()链接处理功能, 但是这个例子并不完全符合我的确切情况,最后在我的process-the-data处理程序中没有引用http响应数据。当我运行它时,浏览器会登录到控制台,&#34; jsonData undefined&#34;
var prevPromise = $.Deferred().resolve();
var recsPerPkt = 20;
var recRqstd = 0;
while(recsRqstd < totalRecsAvailable) {
prevPromise = prevPromise.then(function(){
return $.ajax({
url: 'eventSummaryData',
type: 'get',
cache: false,
data: {StartNdxNum: nextNdxRqst, NumRecords: recsPerPkt}
});
}).then(function (jsonData) {
if (jsonData.ok) {
// Now display the rows/records included in this packet.
displayTrainSummaryRows({"rows": jsonData.rows});
}
},
function(){
$('#error-msg').text('HTTP error: ' + errorThrown);
}
);
recsRqstd += recsPerPkt;
nextNdxRqst = recsRqstd;
}
那么,我如何在序列中强制执行AJAX请求数据的处理 请求最初是由哪些人提出的?提前谢谢。
答案 0 :(得分:2)
我建议使用原生Promises而不是jQuery的延迟对象。它们更具可读性,更易于理解,本机语言本身,并且具有越来越多的浏览器支持(除了所有IE版本)。要考虑浏览器支持,请使用es6-promise之类的polyfill,然后设置。 This article在解释承诺的基础知识方面做得很好。
查看我链接到的那篇文章的部分,标题为“并行和排序”,因为它真正深入探讨了它的工作原理。基本上你需要创建一个promise生成器函数,某种映射需要你做多少个ajax请求(在这种情况下只是一个每次上升20的数组),以及一个sequence
变量来保存之前的承诺已经完成。
var totalRecsAvailable = 10; //generated elsewhere apparently
var recsPerPkt = 20;
var nextNdxRqst = 0;
var recordRanges = [];
var sequence = Promise.resolve(); //initialize to empty resolved promise
//this generates a promise
function getMyData(startPosition) {
return new Promise(function(resolve,reject){
$.ajax({
type: 'GET',
dataType: 'json',
url: 'eventSummaryData',
data: {StartNdxNum: startPosition, NumRecords: recsPerPkt}
success: function(response){resolve(response);},
error: function(response){reject(response);}
});
});
}
//build out array to inform our promises what records to pull & in which order
for (var i = 0; i < totalRecsAvailable; i++) {
recordRanges.push(nextNdxRqst);
nextNdxRqst += recsPerPkt;
}
//loop through record ranges, chain promises for each one
recordRanges.forEach(function(range) {
sequence = sequence.then(function() {
return getMyData(range); // return a new Promise
}).then(function(data) {
//do stuff with the data
addToHtmlTable(data.something);
}).catch(function(error) {
//something went wrong
console.log(error);
});
});
如该文章所述,使用reduce代替forEach
实际上要好一些,但我认为这更清楚发生了什么。
要获得稍快的性能,您应该使用Promise.all()。这需要一个可迭代的(如数组)promises,异步运行这些promises,然后按照传递的顺序将结果保存到数组 。如果其中一个承诺失败,整个过程将失败并给出错误。这听起来就像你需要的一样。例如,你可以这样做:
var recsPerPkt = 20;
var nextNdxRqst = 0;
var totalRecsAvailable = 10; //generated elsewhere apparently
var promises = [];
//this generates a promise
function getMyData(startPosition, recordsNumber) {
return new Promise(function(resolve,reject){
$.ajax({
type: 'GET',
dataType: 'json',
url: 'eventSummaryData',
data: {StartNdxNum: startPosition, NumRecords: recordsNumber}
success: function(response){resolve(response);},
error: function(response){reject(response);}
});
});
}
//create list of promises
for (var i = 0; i < totalRecsAvailable; i++) {
promises.push(getMyData(nextNdxRqst,recsPerPkt));
nextNdxRqst += recsPerPkt;
}
//This will run once all async operations have successfully finished
Promise.all(promises).then(
function(data){
//everything successful, handle data here
//data is array of results IN ORDER they were passed
buildTable(data);
},
function(data){
//something failed, handle error here
logoutError(data);
}
);
这应该让你走上正确的道路。
答案 1 :(得分:1)
我不知道任何jQuery函数可以执行您想要的操作,但这里有一个函数processInOrder
,在所有先前的异步操作都已解决但仍然允许您访问它们之前,它不会执行回调结果
function processInOrder(arr, cb){
if( arr.length > 0 ){
arr[0].then(function(result){
cb(result);
processInOrder(arr.slice(1), cb);
});
}
}
var deferreds = [];
for(var i=0; i<4; i++){
deferreds.push( asyncRequest(i) );
}
processInOrder(deferreds, display);
请注意,虽然我不是肯定的,但我相当确定这种递归形式不会为大量请求中断调用堆栈。
这是jsFiddle