Почему я получаю «неопределенный» и пустой массив [] из вызова Promise.all, включающего асинхронные операции JavaScript, использующие API Azure?

В рамках моего личного проекта, в котором используются API-интерфейсы искусственного интеллекта Azure и Node.js/Экспресс,, я пытаюсь ответить на получить запрос на маршрут /viewText с помощью текст и ключевые слова, извлеченных из загруженного изображения/документа.

Вот код, который должен записывать эти данные в консоль:

app.get(`/viewText`, async (req, res) => {
  const answerReadResult = await readOperation(`${__dirname}\\uploads\\answer`);
  const markReadResult = await readOperation(`${__dirname}\\uploads\\mark`);
  
  Promise.all([
    readOperation(`${__dirname}\\uploads\\answer`),
    keyPhraseExtractor(answerReadResult),
    readOperation(`${__dirname}\\uploads\\mark`),
    keyPhraseExtractor(markReadResult),
  ]).then((data) => {
    console.info("data from Promise.all: ", data);
  });
});

Я ожидал получить две строки от функции readOperation и массив строк от keyPhraseExtractor, но все, что я получил, это: data from Promise.all: [ undefined, [], undefined, [] ]

Вот код функции readOperation (которая берет изображение и возвращает идентифицируемый текст в виде массива строк)

const readOperation = async (path) => {
  fs.readdir(path, (err, files) => {
    if (err) console.info(err);

    files.forEach(async (file) => {
      try {
        const results = await getTextFromImage(
          `${__dirname}\\uploads\\answer\\${file}`
        );
        console.info("data from readOperation: ", results.join(" "));
        return results;
      } catch (err) {
        console.error(err);
      }
    });
  });
};

и журнал: data from readOperation: you must be the change you want to see in the world !

Примечание: эти зарегистрированные данные - это то, что я пытаюсь вернуть из этой функции (без присоединиться("")), но я получаю неопределенный, как видно из Обещание.все

Функция keyPhraseExtractor (показана ниже) ожидает массив строк и должна возвращать ключевые фразы в этих строках (также в виде массива строк).

const keyPhraseExtractor = async (dataFromReadOperation) => {
  let results = dataFromReadOperation;
  try {
    const data = await keyPhraseExtraction(textAnalyticsClient, results);
    console.info("data inside keyPhraseExtractor: ", data);
    return data;
  } catch (err) {
    console.error(err);
  }
};

Лог есть data inside keyPhraseExtractor: []

Ну, если он ловит ошибку, он ничего не возвращает.

epascarello 18.03.2022 18:41

Что за логи, которые над ним, вы видите данные внутри или видите ошибку?

epascarello 18.03.2022 18:42

@epascarello Я поделился журналами для каждой функции под кодом функции и для .then() в app.get, вот что я получаю Promise.all: [ undefined, [], undefined, [] ]. readOperation возвращает неопределенный, и поскольку это неопределенное значение входит в keyPhraseExtractor, я думаю, именно поэтому я получаю пустой массив из keyPhraseExtractor. Следовательно, часть моего вопроса заключается в том, как заставить readOperation возвращать полученные результаты (который должен быть массивом строк)

Fiewor John 18.03.2022 20:10
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
3
51
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

readOperation неправильно. В функции async вы запускаете readDir и передаете ей обратный вызов, но ничто в функции async не ожидает значения обратного вызова (поэтому readDir, вероятно, не будет выполнено к моменту возврата), и в return нет readOperation, поэтому абсолютно возвращает undefined.

Да, у вас есть return results, но это внутри функции стрелки forEachasync. Нет ничего, что могло бы передать это прилагаемому обещанию, что readOperation вернется.

// This is not async, because it's returning a new Promise anyway.
const readOperation = /* NOT ASYNC */ (path) => {
  return new Promise((resolve, reject) => {
    fs.readdir(path, (err, files) => {
      if (err) {
        console.info(err);
        reject(err);       // Outer. Don't forget to stop here.
      }

      // Resolve the outer promise with an inner promise
      // from Promise.all, so getTextFromImage can run in
      // parallel. Also use `map` instead of `forEach` so the
      // return value is an array of Promises (due to the async).
      resolve(Promise.all(files.map(async (file) => {
        try {
          const results = await getTextFromImage(
            `${__dirname}\\uploads\\answer\\${file}`
          );
          console.info("data from readOperation: ", results.join(" "));
          return results.join(" "); // each file's return should
                                    // be a string, right?
        } catch (err) {
          console.error(err);  // Inner.
          throw err;           // Re-throw so it rejects the promise.
        }
      })));
    });
  });
};

Тем не менее, я бы предложил использовать fs API обещаний, чтобы вы не смешивали API-интерфейсы обратного вызова с ошибкой и функции async.

// This is async, because you can await the Promises inside.
const readOperation = async (path) => {
  let files;
  try {
    files = await fsPromises.readdir(path);
  } catch (err) {
    console.info(err);  // Outer.
    throw err;
  }
  // Still use Promise.all here, so the mapping can happen in parallel.
  // You could await this, but async functions that return Promises will
  // unwrap the results anyway: it only affects where rejections come from.
  return Promise.all(files.map(async (file) => {
    try {
      const results = await getTextFromImage(
        `${__dirname}\\uploads\\answer\\${file}`
      );
      console.info("data from readOperation: ", results.join(" "));
      return results.join(" ");
    } catch (err) {
      console.error(err);  // Inner.
      throw err;           // Re-throw so it rejects the promise.
    }
  });
};

Другие вопросы по теме