如何使用JS async / await等待AJAX​​响应

时间:2019-03-24 04:52:19

标签: javascript ajax async-await

我第一次使用Javascript中的async / await函数。我无法让脚本等待AJAX​​响应,然后再继续阅读/使用该响应。

我知道这里已经有很多关于异步/等待功能没有按预期等待的问题,但是其他问题的答案似乎都不适合我。

基本上,我想做的是遍历层名称数组(对于OpenLayers映射)和forEach层名称,我正在发送AJAX调用以检索记录(如果存在)(来自MySQL数据库)。然后我只显示结果,转到下一个图层名称,发送下一个AJAX调用,等等。

这是我的代码:

async function getCellLayers() {
    layerNames = [];
    map.getLayers().forEach(function(layer) {
        if (layer.get('type') == "cell") {
            if (layer.getZIndex() == 100) {
                layerNames.push(layer.get('name'));
                if (layerNames.length == 1) {
                    fullExtent = layer.getSource().getExtent();
                } else {
                    ol.extent.extend(fullExtent, layer.getSource().getExtent());
                }
            }
        }
    });
    return layerNames;
}

async function getRecord(cell_date) {
    $.ajax({
        url: 'rec/getRecord/'+cell_date,
        type: 'get',
        dataType: 'json',
        success: await function(response){
          console.log("getRecord response: "+JSON.stringify(response));
          return response['data'];
      }
    });
}

async function testAsyncAwaitFunction() {
    let layerNames = await getCellLayers();
    layerNames.forEach(async function(layerName) {
        cell_date = layerName.substring(3)+"_"+window['currentImage'].substring(17,25);
        console.log(cell_date+":");
        let cellRecord = await getRecord(cell_date);
        console.log("Matches: "+cellRecord.length);
        console.log("testAsyncAwaitFunction response: "+JSON.stringify(cellRecord));
    });
}

我希望在控制台中看到以下内容:

cell101_20190202:
getRecord response: {"data": [{"id":1,"record":"cell101_20190202","value":"0.8"}]}
Matches: 1
testAsyncAwaitFunction response: {"data": [{"id":1,"record":"cell101_20190202","value":"0.8"}]}
cell102_20190202:
getRecord response: {"data": [{"id":2,"record":"cell102_20190202","value":"0.7"}]}
Matches: 1
testAsyncAwaitFunction response: {"data": [{"id":2,"record":"cell102_20190202","value":"0.7"}]}
[ ... and so on ... ]

但是我却得到了:

cell101_20190202:
cell102_20190202:
(...)
getRecord response: {"data": [{"id":1,"record":"cell101_20190202","value":"0.8"}]}
getRecord response: {"data": [{"id":2,"record":"cell102_20190202","value":"0.7"}]}
(...)
getRecord response: {"data": [{"id":14,"record":"cell202_20190202","value":"0.6"}]}
(200x) Uncaught (in promise) TypeError: Cannot read property 'length' of undefined
getRecord response: {"data": [{"id":15,"record":"cell204_20190202","value":"0.5"}]}
(...)

我从没见过JSON.stringify前缀为testAsyncAwaitFunction response的行,大概是因为该console.log命令之前的行试图获取cellRecord的长度,但由于AJAX响应尚未到达而失败

我怀疑下面这行将是关键:

let cellRecord = await getRecord(cell_date);

但是我无法弄清楚为什么似乎没有一个“正在等待”的人,即使上面几行的另一行看起来也很好:

let layerNames = await getCellLayers();

非常感谢能更好地使用async / await的人员提供的帮助。我更加习惯于PHP和Python,并且很难将自己的思维方式转变为异步思考。

3 个答案:

答案 0 :(得分:1)

getRecord更改为此

function getRecord(cell_date) {
    return $.ajax({
        url: 'rec/getRecord/'+cell_date,
        type: 'get',
        dataType: 'json'
    }).then(function(response){
      console.log("getRecord response: "+JSON.stringify(response));
      return response['data'];
  });
}

从代码的所有位置删除asyncawait关键字,除了这两部分的testAsyncAwaitFunction之外:

async function testAsyncAwaitFunction()

let cellRecord = await getRecord(cell_date);

否则,您将不需要它们。

以前不会起作用,因为您的函数需要返回一个包含数据的Promise。您应该阅读JavaScript promises。异步/等待在很大程度上是这些的语法糖,用于处理异步代码。您仅有的实际异步代码是对getRecord的调用。

答案 1 :(得分:1)

关于异步要记住的事情是,任何以异步为前缀的函数都应返回Promise。 getRecord应该返回您所拥有的。另外,虽然外部函数testAsyncAwaitFunction是异步的,并且forEach回调是异步的,但是您没有什么等待您的forEach的所有诺言得以解决。

您想要这种模式:

async function testAsyncAwaitFunction() {
    let layerNames = await getCellLayers();
    const promises = [];
    layerNames.forEach(function(layerName) {
        promises.push(getRecord(cell_date));
    });
    const cell_records = await Promise.all(promises);
    cell_records.forEach(function(cell_record, idx) {
        cell_date = layerNames[idx].substring(3)+"_"+window['currentImage'].substring(17,25);
        console.log(cell_date+":");
        console.log("Matches: "+cellRecord.length);
        console.log("testAsyncAwaitFunction response: "+JSON.stringify(cellRecord));
    })
}

答案 2 :(得分:1)

这里有两件事: -您的Promise函数不会返回forEach,因此await不会等待任何东西 -async function getRecord(cell_date) { return $.ajax({ url: 'rec/getRecord/'+cell_date, type: 'get', dataType: 'json', }) .then(response => response.data); } 无法与异步函数一起使用,因为该实现不会等待。

对于第一个问题,您可以通过执行以下操作来解决它:

async function testAsyncAwaitFunction() {
    let layerNames = await getCellLayers();
    for (layerName of layerNames) {

        cell_date = layerName.substring(3)+"_"+window['currentImage'].substring(17,25);
        console.log(cell_date+":");
        let cellRecord = await getRecord(cell_date);
        console.log("Matches: "+cellRecord.length);
        console.log("testAsyncAwaitFunction response: "+JSON.stringify(cellRecord));

    }
}

对于第二个问题,您可以通过以下方式运行循环来实现:

Promise.all

但是,这样做会使所有内容一一运行。通过发送请求,然后使用const promises = [] for (layerName of layerNames) { cell_date = layerName.substring(3)+"_"+window['currentImage'].substring(17,25); console.log(cell_date+":"); promises.push(getRecord(cell_date)); } const records = await Promise.all(promises) 来等待所有请求完成,您甚至可以做得更好:

(i-1, j-1), (i-1, j), (i-1, j+1), (i, j-1), (i, j+1), (i+1, j-1), (i+1, j), (i+1, j+1).