贝娄是从数据库获取列表,然后为每个列表项请求更多数据并为每个项目绘制Google图表的代码。除了对更多数据的ajax调用之外,everything一切正常,返回的数据顺序与原始列表的顺序不同。根据调用方式的不同,列表有不同的计数,但是绘制了二十多个图表。数据库很大,并且怀疑这是ajax请求未按相同顺序返回的主要原因。
我如何更改我的代码以在上一个返回之前停止另一个ajax调用
function getList(fueltype, Date1) {
document.getElementById('charts').innerHTML = "";
var sd = new Date(Date1);
var y = sd.getFullYear();
var m = sd.getMonth();
var d = sd.getDate();
var ed = new Date(y,m,d+1,0,0,0,0);
var startDate = formatDate(sd);
var fuelsearch = '';
var dbFile = '';
var endDate = formatDate(ed);
switch(fueltype){
case 'Coal':
fuelsearch = 'COAL';
dbFile = 'getJSONdata.php';
break;
case 'CCGT':
fuelsearch = 'CCGT';
dbFile = 'getJSONdata.php';
break;
case 'Nuclear':
fuelsearch = 'NUCLEAR';
dbFile = 'getJSONdata.php';
break;
case 'OCGT':
fuelsearch = 'OCGT';
dbFile = 'getJSONdata.php';
break;
case 'Other':
fuelsearch = 'OTHER';
dbFile = 'getJSONdata.php';
break;
case 'Pump Storage':
fuelsearch = 'PS';
dbFile = 'getJSONdataWithMIL.php';
break;
case 'Wind':
fuelsearch = 'WIND';
dbFile = 'getJSONdata.php';
break;
case 'Non Pump Storage Hydro':
fuelsearch = 'NPSHYD';
dbFile = 'getJSONdata.php';
break;
default:
}
$.ajax({
url: "getBmuList.php",
dataType: 'json',
data: {
fuel: fuelsearch
}
}).done(function (listData) {
// draw chart for each id
listData.forEach(function (itemId) {
//console.log(itemId);
drawChart(itemId,startDate,endDate,dbFile);
});
}).fail(function (jq, text, errMsg) {
console.log(text + ': ' + errMsg);
});
}
// This function takes a bmu and gets data in JSON format and draws a google chart
function drawChart(itemId,startDate,endDate,dbFile) {
var bmu = itemId.itemID;
console.log(bmu);
$.ajax({
url: dbFile,
dataType: 'json',
data: {
Id: bmu,
date1: startDate,
date2: endDate
}
}).done(function (jsonData) {
console.log(bmu);
var sd = new Date(startDate);
var y = sd.getFullYear();
var m = sd.getMonth();
var d = sd.getDate();
//console.log(sd);
//console.log(new Date(y,m,d,0,0,0));
var data = new google.visualization.DataTable(jsonData);
var options = {
title: bmu,
width: 495,
height: 300,
series: {
0: { lineWidth: 1, pointSize: 1.1 },
1: { lineWidth: 1, pointSize: 1.1},
2: { lineWidth: 1, pointSize: 1.1},
3: { lineWidth: 1, pointSize: 1.1}},
hAxis: {
textStyle:{fontSize: 10},
format: 'HH:mm',
minValue: new Date(y,m,d,0,0,0),
maxValue: new Date(y,m,d+1,0,0,0),
viewWindow:{
min: new Date(y,m,d,0,0,0),
max: new Date(y,m,d+1,0,0,0)
},
},
vAxis: {
textStyle:{fontSize: 10},
},
chartArea: {backgroundColor: '#fffff0'},
};
// create new div for chart
var div = document.createElement("div");
div.style.width = "500px";
div.style.height = "330px";
div.style.float = "left";
div.style.border = "thin solid #DCDCDC";
div.id = itemId.itemID + "_div";
container = document.getElementById('charts').appendChild(div);
var chart = new google.visualization.ScatterChart(container);
chart.draw(data, options);
//google.visualization.events.addListener(chart, 'click', selectHandler);
}).fail(function (jq, text, errMsg) {
console.log(text + ': ' + errMsg);
});
}
最佳答案
Ajax本质上是异步的,因此所有请求都按顺序触发,但是响应一旦返回便会得到响应。
jQuery $.ajax()
函数具有async选项,您可以将其设置为false使其变为同步(返回数据而不是传递给成功的回调,或者抛出错误而不是在发生错误时调用错误)。
但是此选项已被弃用,很快将被删除,因此依靠它不是一个好主意。
因此,您需要使用一些真正的异步模式。而且,我认为,promise是最好的(在很旧的浏览器中可能不支持它们,但是如果需要的话,可以使用polyfill支持它们。
就是说,您的drawChart()
函数的模式不是很好,因为它不仅执行其名称所指(绘制图表),而且还异步请求数据,因此将它们分开是一个很好的主意行为。
当然,您可以简单地使其返回承诺并以瀑布样式链接所有呼叫,以便每个请求+绘图在先前完成之后开始。但是,如果(据我认为理解)这些请求都没有改变其他请求的结果(您只是在要求渲染顺序),唯一的区别就是您的代码将比实际需要的速度慢得多。
...因此您的新drawChart()
函数将只是您在其内部.done()
调用中作为$.ajax()
回调提供的匿名函数。
下一步将以这种方式修改.done()
函数内部$.ajax()
调用的getList()
回调:
$.ajax({
...
}).done(function(listData){
Promise.all(
listData.map(function(itemId) {
return new Promise(function(resolve, reject) {
// Code removed from your original drawChart() function
var bmu = itemId.itemID;
console.log(bmu);
$.ajax({
...
})
.done(resolve)
.fail(reject);
});
})
)
.then(function(listDataArr){
// Here all (concurrent) requests finished.
// ...and their results are in right order in listDataArr.
listDataArr.map(drawChart);
})
.catch(reject);
}).fail(...);
希望能帮助到你。
这不是最好的方法,但我尝试使它与您的代码尽可能相似,以使您更容易理解最小的要求更改。
编辑:另一方面,我发现您可能不完全需要按顺序渲染它们,即使按随机顺序渲染也足以按该顺序放置它们。
如果是这样,那么您可以使用另一种更简单的策略,根本不需要使用promise,除了需要更少的代码更改外,它还可以更快地运行,并且据我所愿,它可以提供更好的用户体验:
它包括在开始请求它们的数据并呈现它们之前,为每个图表简单地创建和放置容器(同步)。
例如:
var charts = $("#charts");
var containers = listData.map(function(itemId){
return $("<div></div")
.addClass(itemId+"_div")
.appendTo(charts);
});
// Rendering process here.
您可以使用原始的实现方式,唯一的区别是如下所述处理div,而不是每次都创建一个新的实现:
var div = $("div."+itemId+".div);
…甚至,最好使用容器数组(或用下面的代码重新编写以产生“ itemId:容器”对象)。但我留给您选择。
关于javascript - 循环中的多个ajax调用未按被调用的相同顺序返回,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/46773308/