Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/jquery/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 循环中的多模块ajax调用返回的顺序与调用的顺序不同_Javascript_Jquery_Ajax - Fatal编程技术网

Javascript 循环中的多模块ajax调用返回的顺序与调用的顺序不同

Javascript 循环中的多模块ajax调用返回的顺序与调用的顺序不同,javascript,jquery,ajax,Javascript,Jquery,Ajax,下面的代码从数据库中获取列表,然后为每个列表项请求更多数据,并为每个项绘制谷歌图表。除了ajax对更多数据的调用没有以与原始列表相同的顺序返回之外,其他一切都正常工作。根据调用方式的不同,列表有不同的计数,但绘制的图表超过20个。数据库很大,这可能是ajax请求没有按相同顺序返回的主要原因 如何修改代码以在前一个ajax调用返回之前停止另一个ajax调用 function getList(fueltype, Date1) { document.getElementById('charts

下面的代码从数据库中获取列表,然后为每个列表项请求更多数据,并为每个项绘制谷歌图表。除了ajax对更多数据的调用没有以与原始列表相同的顺序返回之外,其他一切都正常工作。根据调用方式的不同,列表有不同的计数,但绘制的图表超过20个。数据库很大,这可能是ajax请求没有按相同顺序返回的主要原因

如何修改代码以在前一个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来实现这一点


在ajax调用中添加async:false属性

async:false
添加到
ajax
调用中

从某种程度上说

请不要因为不推荐使用
async:false
。您将在浏览器中收到一些警告。如果你不想要这些警告,我建议你重新评估你的方法

而且, 跨域请求和
数据类型:“jsonp”
请求不支持同步操作

在你的情况下,看起来是这样的

 $.ajax({
url: dbFile,
dataType: 'json',
data: {
    Id: bmu,
    date1: startDate,
    date2: endDate },
async: false
}).done(function (jsonData) {
  // Do Stuff
});

Ajax本质上是异步的,所以所有请求都是按顺序触发的,但响应一回来就会被处理

jQuery
$.ajax()
函数有一个异步选项,您可以将其设置为false,使其成为同步的(返回数据而不是传递给success回调,或者在发生错误时抛出数据而不是调用error one)

但是这个选项已经被弃用,很快就会被删除,所以依赖它不是一个好主意

因此,您需要使用一些真正的异步模式。而且,在我看来,承诺是最好的(它们可能在非常旧的浏览器中不受支持,但如果您需要的话,可以使用polyfill来支持它们)

这就是说,您的
drawChart()
函数的模式不太好,它不做只做它的名字所说的事情(绘制图表),而是异步地请求数据,因此将这些行为分开是一个非常好的想法

当然,您可以简单地让它返回一个承诺,并以瀑布式样式链接所有调用,以便每个请求+绘图在上一次完成后开始。但是如果(我认为可以理解)这些请求中没有一个会改变其他请求的结果(您只是要求呈现顺序)唯一的区别是你的代码比实际需要的要慢得多

…因此,新的
drawChart()
函数将只是您在其内部
$.ajax()调用中作为
.done()
回调提供的匿名函数

下一步是修改
.done()
调用
$.ajax()
函数内部的
.done()
回调,方法如下:

$.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(...);
希望能有帮助

这并不是最好的方法,但我试着尽可能地与您的代码相似,以便更容易理解所需的最小更改

编辑:另一方面,我发现您可能不需要精确地按顺序渲染它们,而且即使是按随机顺序渲染,也可以将它们按该顺序放置

如果这是真的,那么您就有了另一个更简单的策略,它根本不需要使用承诺,而且,除了需要对代码进行更少的更改之外,它的速度要快得多,而且在我看来,它提供了更好的用户体验:

它包括在开始请求和呈现数据之前,为每个图表创建并放置容器(同步)

例如:

var charts = $("#charts");
var containers = listData.map(function(itemId){
    return $("<div></div")
        .addClass(itemId+"_div")
        .appendTo(charts);
});
// Rendering process here.

…甚至,使用containers数组(或稍微重写下面的代码以生成“itemId:container”对象)会更好.但我让你自己选择。

你应该看看如何在上一个ajax调用返回之前将我的代码更改为
停止
另一个ajax调用,你的意思是
开始
还是
停止
?异步调用不是同步的,因此如果顺序比你需要重新考虑你的方法更重要。为什么否决?我认为这是一个有用的方法回答不仅是OP,还有其他正在寻找答案的人。如果不投反对票,不留下理由,这是没有帮助的。给你一票赞成票。我们一直在努力解决这个问题,但一直在努力从listDataArr.map(drawChart)将图表数据获取到drawChart函数;我需要将json数据放入新函数DrawChart的DataTable中。我没有测试任何东西:我只是试图展示一些指导原则来帮助您解决问题。它可能包含我自己的错误,或者您也可能需要修复其他问题。如果您继续在这方面苦苦挣扎,请编辑您的问题,添加更新的方法,以便我们能够分析正在发生的事情……另一方面,我只是随意地编辑了我的回答,添加了一个“编辑”部分,可能不那么礼貌,但更简单(这意味着它需要对您原来的解释进行更少的更改)和(在我的建议中)更好的用户体验,因为它会继续尽可能快地呈现内容,但位置正确。也许你会对尝试它感兴趣……另外,回答你的评论,
listdatarr.map(drawChart)
calls
drawChart()
对于每个listDataArr项,将该项作为第一个参数传递,并将其在数组中的位置作为第二个参数传递(即使是函数也无法预料)。请记住,在我的建议中,
drawChart()
是您在原始
drawChart()中调用的
.done()
回调函数
只需要一个参数的函数。另外请注意,如果您需要执行其他操作,您始终可以调用另一个函数(即使是在InLine和/或unnamed中),该函数最后在其内部调用
drawChart()
。啊!
var charts = $("#charts");
var containers = listData.map(function(itemId){
    return $("<div></div")
        .addClass(itemId+"_div")
        .appendTo(charts);
});
// Rendering process here.
var div = $("div."+itemId+".div);