es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿Por qué esperar dentro de una función asíncrona no funciona para los módulos fs?

Estoy tratando de leer un archivo sample.json a través de mi código en js. Primero, mi programa busca el archivo sample.json en cada carpeta dentro de la ruta especificada. Luego lee el archivo sample.json si está disponible y obtiene los datos. Pero el await utilizado no funciona como se espera y simplemente pasa el objeto vacío a la función que lo llama antes de que se complete la ejecución de las funciones asíncronas. He adjuntado la imagen del problema.

    async function getAvailableJson(filesPath) {
    let detectedJson = {};
    let folders = await fs.promises.readdir(filesPath);
    folders.forEach(async function(folder) {
        await fs.promises.access(path.join(filesPath, folder, "Sample.json")).then(async function() {
                jsonData = await fs.promises.readFile(path.join(filesPath, folder ,"Sample.json"))
                const directory = JSON.parse(jsonData)
                const hashvalue = Hash.MD5(jsonData)
                detectedJson[directory["dirName"]] = {
                                    name: directory["dirName"],
                                    version: directory["dirVersion"],
                                    hash: hashvalue
                                }
                                console.log(detectedJson);
                            }).catch(function(err) {
                                if(err.code === "ENOENT")
                                {}
                            });
                    });

    return detectedJson;
}

No quiero usar ninguna función de sincronización ya que crea bloqueos innecesarios. También he intentado con las funciones fs.readdir, fs.access y fs.readFile. ¿Podría alguien señalar lo que estoy haciendo mal aquí ya que soy nuevo en Node.js? Gracias de antemano.

Imagen de muestra: enlace de imagen

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    Problema con await al leer un archivo sample.json

    El código proporcionado intenta leer un archivo JSON de muestra en una ruta especificada mediante la verificación de cada carpeta dentro de la ruta. Sin embargo, el problema encontrado es que la función esperada no funciona como se espera y simplemente pasa un objeto vacío a la función de llamada antes de que la función asíncrona complete su ejecución.

    El código proporcionado utiliza los siguientes módulos y funciones:

    • Node.js: Un entorno de ejecución de JavaScript construido sobre el motor V8 de Chrome.
    • async-await: Un azúcar sintáctico para promesas que permite el uso de await para escribir código asíncrono de manera síncrona.
    • node-modules: Una carpeta donde se almacenan todos los módulos de Node.js.
    • fs: Un módulo incorporado en Node.js que permite interactuar con el sistema de archivos.
    • async.js: Un módulo que proporciona una colección de utilidades para trabajar con JavaScript asincrónico.

    La función getAvailableJson() es una función asíncrona que recibe un parámetro filesPath que representa la ruta donde se encuentra el archivo JSON de muestra. La función lee el contenido de la carpeta y verifica si el archivo Sample.json existe dentro de cada carpeta. Si existe, lee el contenido del archivo, recupera los datos necesarios y los guarda en un objeto llamado detectedJson. Una vez que se han verificado todas las carpetas, la función devuelve el objeto detectedJson.

    El problema con el código es que el método forEach() que se está utilizando no es compatible con async-await. El método forEach() no espera a que las promesas dentro de él se completen, por lo que la función devuelve un objeto detectedJson vacío antes de que las promesas se resuelvan. Para solucionar este problema, el código necesita usar un bucle for...of o map con async-await.

    Para usar un bucle for...of, reemplace el método forEach() con:

    for (const folder of folders) {
       try {
          await fs.promises.access(path.join(filesPath, folder, "Sample.json"));
          jsonData = await fs.promises.readFile(path.join(filesPath, folder , "Sample.json"));
          const directory = JSON.parse(jsonData);
          const hashvalue = Hash.MD5(jsonData);
          detectedJson[directory["dirName"]] = {
                name: directory["dirName"],
                version: directory["dirVersion"],
                hash: hashvalue
          };
          console.log(detectedJson);
       } catch (err) {
          if (err.code === "ENOENT") {
             // no hacer nada
          }
       }
    }
    

    Alternativamente, se puede utilizar un map con async-await:

    const detectedJson = await Promise.all(folders.map(async (folder) => {
       try {
          await fs.promises.access(path.join(filesPath, folder, "Sample.json"));
          const jsonData = await fs.promises.readFile(path.join(filesPath, folder , "Sample.json"));
          const directory = JSON.parse(jsonData);
          const hashvalue = Hash.MD5(jsonData);
          return {
                name: directory["dirName"],
                version: directory["dirVersion"],
                hash: hashvalue
          };
       } catch (err) {
          if (err.code === "ENOENT") {
             return null;
          }
       }
    })).then((result) => {
       return result.filter((item) => item !== null).reduce((prev, curr) => {
          prev[curr.name] = curr;
          return prev;
       }, {});
    });
    

    En esta implementación, la función map() devuelve un array de promesas que se resuelven más tarde usando Promise.all(). El método finally() filtra cualquier valor null y crea un nuevo objeto llamado detectedJson que contiene los datos necesarios.

    En resumen, el problema con el código es que el método forEach() no espera a que las promesas se completen, lo que resulta en un objeto detectedJson vacío. Para solucionar esto, se puede usar un bucle for...of o map con async-await, lo que permite que la función espere a que las promesas se completen antes de devolver el objeto detectedJson.

Comments are closed.