В рамках моего личного проекта, в котором используются 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 Я поделился журналами для каждой функции под кодом функции и для .then()
в app.get
, вот что я получаю Promise.all: [ undefined, [], undefined, [] ]
. readOperation возвращает неопределенный, и поскольку это неопределенное значение входит в keyPhraseExtractor, я думаю, именно поэтому я получаю пустой массив из keyPhraseExtractor. Следовательно, часть моего вопроса заключается в том, как заставить readOperation возвращать полученные результаты (который должен быть массивом строк)
readOperation
неправильно. В функции async
вы запускаете readDir
и передаете ей обратный вызов, но ничто в функции async
не ожидает значения обратного вызова (поэтому readDir
, вероятно, не будет выполнено к моменту возврата), и в return
нет readOperation
, поэтому абсолютно возвращает undefined
.
Да, у вас есть return results
, но это внутри функции стрелки forEach
async
. Нет ничего, что могло бы передать это прилагаемому обещанию, что 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.
}
});
};
Ну, если он ловит ошибку, он ничего не возвращает.