Search code examples
node.jsexpressasynchronouspromisereaddir

How can I send data to the client after use readdir inside a readdir


I need read a folder called 'curvas'. A lot of folders are inside 'curvas' and i'm using readdir to get them. After get the folders inside 'curvas', i'm doing a foreach and using readdir to list the files (files inside the folders that is inside 'curvas').

The problem is that i can only access the variable inside the internal readdir (i tested with console.log).

Q: How can I access this variables and respond to the client with res. ?

Here's how far I came:

exports.getInserted = async function (req, res) {

    var teste = await getFilesNames(); // HERE I NEED TO GET THIS FILES NAMES WITH FOLDERS
    console.log(teste); // AND THEM PASSING TO THE CLIENT WITH RES.SEND()

};

function getFilesNames() {
    return new Promise(function (resolve, reject) {

        const chartFolder = './curvas/';
        var fileNames = [];

        fs.readdir(chartFolder, (err, folders) => {

            if (err) {
                reject(new Error("Erro ao ler os arquivos."));
            }
            folders.forEach(folder => {
                fs.readdir(chartFolder + folder, (err, files) => {
                    fileNames = files;
                    console.log(files) // ----- HERE I CAN SEE ALL FILES AND LIST WITH THEIR FOLDERS.
                });
            });
            // I NEED USE resolve(fileNames) HERE, BUT IS EMPTY!!
        });
    });
};

Thank you!

[EDIT]

Solution: Guided by @omarwaleed

    exports.getInserted = async function (req, res) {

    // Envia os arquivos das pastas de curvas para o cliente.
    var data = await getFilesNames();
    res.status(200).send(data);

};

function getFilesNames() {
    return new Promise(function (resolve, reject) {

        const chartFolder = './curvas/';

        // take care. I've turned it into an async function here
        fs.readdir(chartFolder, async (err, folders) => {

            if (err) {
                reject(new Error("Erro ao ler os arquivos."));
            }
            let promiseArray = [];
            folders.forEach(folder => {
                promiseArray.push(
                    new Promise((resolve, reject) => fs.readdir(chartFolder + folder, (err, files) => {
                        if (err) {
                            reject(err);
                        }
                        resolve({
                            folder: folder,
                            files: files
                        });
                    }))
                )
            });
            let results = await Promise.all(promiseArray);
            resolve(results)
        });
    });
};

Solution

  • Using resolve in place of the comment // I NEED USE resolve(fileNames) HERE, BUT IS EMPTY!! will result in an undefined resolve statement since the second fs.readdir will run asynchronously which means that the directory will be read AFTER your code resolves. To solve this problem I advise you to wrap fs.readdir with promises where you can await the reading of all files and resolve the response
    Here's how your function will look like

    function getFilesNames() {
        return new Promise(function (resolve, reject) {
    
            const chartFolder = './curvas/';
            var fileNames = [];
    
            // take care. I've turned it into an async function here
            fs.readdir(chartFolder, async (err, folders) => {
    
                if (err) {
                    reject(new Error("Erro ao ler os arquivos."));
                }
                let promiseArray = [];
                folders.forEach( folder => {
                promiseArray.push(
                  new Promise((resolve, reject)=>fs.readdir(chartFolder + folder, (err, files)=>{
                    if(err){
                      reject(err)
                    }
                    resolve(files)
                  }))
                )
            });
            let results = await Promise.all(promiseArray);
                resolve(results)
            });
        });
    };