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

Gar*_*nes 2 javascript ajax async-await

我第一次使用 Javascript 中的异步/等待函数。我无法让我的脚本等待 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));
    });
}
Run Code Online (Sandbox Code Playgroud)

我期望在控制台中看到类似的内容:

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 ... ]
Run Code Online (Sandbox Code Playgroud)

但我得到的是这个:

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"}]}
(...)
Run Code Online (Sandbox Code Playgroud)

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

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

let cellRecord = await getRecord(cell_date);
Run Code Online (Sandbox Code Playgroud)

但我不明白为什么那个似乎没有“等待”,尽管上面几行的另一行似乎工作得很好:

let layerNames = await getCellLayers();
Run Code Online (Sandbox Code Playgroud)

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

Fra*_* P. 7

这里有两件事: - 你的getRecord函数不返回 aPromise因此,等待不会等待任何东西 -forEach不能使用异步函数,因为实现不等待。

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

async function getRecord(cell_date) {
    return $.ajax({
        url: 'rec/getRecord/'+cell_date,
        type: 'get',
        dataType: 'json',
    })
    .then(response => response.data);
}
Run Code Online (Sandbox Code Playgroud)

对于第二个问题,您可以通过这样运行循环来完成:

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));

    }
}
Run Code Online (Sandbox Code Playgroud)

但这样做会让一切都一一运行起来。您可以通过发送请求然后等待所有请求完成来做得更好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)
Run Code Online (Sandbox Code Playgroud)