Как использовать JS async / await для ожидания ответа AJAX - PullRequest
0 голосов
/ 24 марта 2019

Я впервые работаю с асинхронными / ожидающими функциями в 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));
    });
}

Я ожидаю увидеть что-то вродеэто в консоли:

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 ]

1 голос
/ 24 марта 2019

Следует помнить об асинхронности, что любая функция с префиксом async должна возвращать 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));
    })
}
1 голос
/ 24 марта 2019

Две вещи здесь: - Ваша getRecord функция не возвращает Promise, поэтому ожидающий ничего не ждет - forEach не может работать с асинхронными функциями, так как реализация не ожидает.

Для первой проблемы вы можете решить ее, выполнив:

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)
1 голос
/ 24 марта 2019

измените 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'];
  });
}

И удалите оба ключевых слова async и await из любого места в вашем коде, кроме testAsyncAwaitFunction в этих двух частях:

async function testAsyncAwaitFunction()

и

let cellRecord = await getRecord(cell_date);

В противном случае они вам не нужны.

Это не сработало бы раньше, потому что вашФункция должна вернуть обещание, содержащее данные.Вы должны прочитать о обещаниях JavaScript .Async / Await является в значительной степени синтаксическим сахаром для них и используется для обработки асинхронного кода.Единственный действительный асинхронный код, который у вас есть, это вызов getRecord.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...