Como parte de mi proyecto personal que utiliza las API de Azure AI y Node.js/Express, intento responder a una solicitud de obtención de una ruta /viewText
con texto y frases clave extraídas de una imagen o un documento cargado.
Aquí está el código que debería registrar esos datos en la consola:
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.log("data from Promise.all: ", data); }); });
Esperaba recibir dos cadenas de la función readOperation y una matriz de cadenas de keyPhraseExtractor, pero todo lo que obtengo es: data from Promise.all: [ undefined, [], undefined, [] ]
Aquí está el código para la función readOperation (que toma una imagen y devuelve el texto identificable como una matriz de cadenas)
const readOperation = async (path) => { fs.readdir(path, (err, files) => { if (err) console.log(err); files.forEach(async (file) => { try { const results = await getTextFromImage( `${__dirname}\\uploads\\answer\\${file}` ); console.log("data from readOperation: ", results.join(" ")); return results; } catch (err) { console.error(err); } }); }); };
y el registro es: data from readOperation: you must be the change you want to see in the world !
NB: estos datos registrados son lo que estoy tratando de devolver de esta función (sin la combinación ("") ) pero me estoy quedando indefinido como se desprende de Promise.all
La función keyPhraseExtractor (que se muestra a continuación) espera una matriz de cadenas y debe devolver las frases clave en esas cadenas (también como una matriz de cadenas)
const keyPhraseExtractor = async (dataFromReadOperation) => { let results = dataFromReadOperation; try { const data = await keyPhraseExtraction(textAnalyticsClient, results); console.log("data inside keyPhraseExtractor: ", data); return data; } catch (err) { console.error(err); } };
El registro son data inside keyPhraseExtractor: []
readOperation
es incorrecta. Dentro de la función async
, está iniciando readDir
y pasándole una devolución de llamada, pero nada en la función async
espera el valor de devolución de llamada (por lo que es probable que readDir
no haya terminado para cuando regrese), y no hay return
en readOperation
, por lo que absolutamente devuelve undefined
.
Sí, tiene return results
, pero eso está dentro de la función de flecha async
forEach
. No hay nada que pase eso a la promesa adjunta que devuelve 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.log(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.log("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. } }))); }); }); };
Dicho esto, sugeriría usar la API de fs
Promises para no mezclar las API de devolución de llamada err-first y las funciones 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.log(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.log("data from readOperation: ", results.join(" ")); return results.join(" "); } catch (err) { console.error(err); // Inner. throw err; // Re-throw so it rejects the promise. } }); };