This question already has answers here:
How do I return the response from an asynchronous call?
                            
                                (38个答案)
                            
                    
                在8个月前关闭。
        

    

我对JavaScript还是很陌生,但是程序的基本前提是进行API调用,然后将数据转换为表。我已经测试了buildHtmlTable函数,并且该函数与预先填充了静态数据(不是来自API)的示例数组可以正常工作。

buildHtmlTable函数中,console.log(myList.length)返回0。这很可能是问题出处,因为如果length为0,则for (var i = 0; i < myList.length; i++根本不会运行。

我也尝试过使用.push将数据添加到表中,并且似乎遇到了相同的错误。

这是我的代码:

<body onLoad="buildHtmlTable('#excelDataTable')">
  <table id="excelDataTable" border="1">
  </table>
</body>

<script>

  var myList = [];


  function getAPIData() {
    // Create a request variable and assign a new XMLHttpRequest object to it.
    var request = new XMLHttpRequest()


    // Open a new connection, using the GET request on the URL endpoint
    request.open('GET', '/api/table=1/records/', true)
    request.onload = function () {
      // Begin accessing JSON data here
      var data = JSON.parse(this.response)

      n = 0

      if (request.status >= 200 && request.status < 400) {
        data.forEach(record => {
          myList[n] = (record.data);
          n++;
          //console.log(record.data.name)
        })
      } else {
        console.log('error')
      }
    }

    request.send()
    console.log('fin')
  }



  // Builds the HTML Table out of myList.
  function buildHtmlTable(selector) {
    getAPIData()
    console.log(myList.length)

    console.log(1)

    var columns = addAllColumnHeaders(myList, selector);

    console.log(1.1)
    console.log(myList.length)

    for (var i = 0; i < myList.length; i++) {
      console.log(1.2)

      var row$ = $('<tr/>');
      console.log(1.3)

      for (var colIndex = 0; colIndex < columns.length; colIndex++) {
        var cellValue = myList[i][columns[colIndex]];
        if (cellValue == null) cellValue = "";
        row$.append($('<td/>').html(cellValue));
      }
      $(selector).append(row$);
    }

    console.log(2)

  }

  // Adds a header row to the table and returns the set of columns.
  // Need to do union of keys from all records as some records may not contain
  // all records.
  function addAllColumnHeaders(myList, selector) {
    var columnSet = [];
    var headerTr$ = $('<tr/>');

    for (var i = 0; i < myList.length; i++) {
      var rowHash = myList[i];
      for (var key in rowHash) {
        if ($.inArray(key, columnSet) == -1) {
          columnSet.push(key);
          headerTr$.append($('<th/>').html(key));
        }
      }
    }
    $(selector).append(headerTr$);

    return columnSet;
  }
</script>


至于请求的数据,这就是返回的JSON的样子:

[
    {
        "id": 1,
        "data": {
            "name": "John Doe",
            "id": "5d7861f38319f297df433ae1"
        }
    },
    {
        "id": 2,
        "data": {
            "name": "John deer",
            "id": "5d7861f38319f297df433ae1"
        }
    },
    {
        "id": 3,
        "data": {
            "name": "Jane Doe",
            "id": "5d79126f48ca13121d673300"
        }
    }
]


有什么想法我在这里错了吗?谢谢。

编辑:这是我使用fetch的实现。但是,我仍然得到长度为0的数组。

  async function getAPIData() {
    const response = await fetch('/api/table=1/records/')
    const myJson = await response.json();
    myJson.forEach(record => {
      myList.push(record.data);
    })
  }

最佳答案

XMLHttpRequest是异步的,这意味着您的其余代码不会在它们运行之前等待它们完成。当您调用getAPIData()时,它开始发出请求,但是在请求完成之前(因此在填充列表之前),它会转到buildHtmlTable的下一行。您应该做的是在getAPIData函数外部调用buildHtmlTable函数,然后在XHR请求的onload回调中调用buildHtmlTable。这将确保在运行HTML构建功能时加载和填充数据。

您也可以切换为使用fetch代替XMLHttpRequest;由于fetch返回承诺,因此您可以使用ES6 async / await语法在buildHtmlTable函数内部的代码继续之前等待API响应。但这是思考AJAX和异步行为的新方法,因此,如果您不习惯,我会说坚持我的第一个建议。

07-24 14:58