Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

295
Visualizações
fs.readfile changes scope of global array and it can't be used outside it

I have 2 sections of code 1) that is called by 2nd to populate the array and write it into a file.

async function timeSeries(obj) {
    data = [
        {
            original_value: []
        }
    ]

    //read file named as passed object's _id
    await fs.readFile("./api/assignment_data/" + obj._id + ".json", "utf-8", function read(err, datas) {
        if (err) {
            throw err;
        }
        const filedata = JSON.parse(datas)
        filedata.map(line => data[0].original_value.push(line.original_value))
    })

    setTimeout(() => {
        try {
            fs.writeFileSync("./api/timeseries.json", JSON.stringify(data), { encoding: 'utf8', flag: 'w' })
        } catch (error) {
            console.log(error)
        }
    }, 300);

}

The problem is, I can't access the global data array above after using it inside the fs.readfile function ( callback scope hell problem), I had to setTimeout then I am able to write it inside a file using another fs.writeFileSync function ( if I return the array I get a promise, I want data).How do I solve this? instead of writing it into another file and using it inside another route(below) how can I directly return the array in the second route and pass it as a json res?

section 2)

router.route("/api/debug/:num").get((req, res) => {

    fs.readFile("./api/assignment_data/metrics.json", "utf8", function read(err, data) {
        if (err) {
            console.log(err);
        }
        const objdata = JSON.parse(data)
        timeSeries(objdata[req.params.num])
    })

    fs.readFile("./api/timeseries.json", "utf8", function read(err, data) {
        if (err) {
            console.log(err);
        }
        const objdata = JSON.parse(data)
        res.json(data)
    })
})
about 4 years ago · Juan Pablo Isaza
3 Respostas
Responde à pergunta

0

If you use fs.readFile and want to do an action after the file has been read, you must do the action (write and read a file in your case) inside the callback function. Also, you can use fs.readFileSync if you can read synchronously.

about 4 years ago · Juan Pablo Isaza Relatório

0

First off, we need to explain a few things:

fs.readFile() is non-blocking and asynchronous. That means that when you call it, it starts the operation and then returns immediately and starts the execute the code that comes right after it. Then, some time later, it calls its callback.

So, your code is:

  1. Calling fs.readFile()
  2. Then, immediately setting a timer
  3. Then, it's an indeterminate race between the fs.readFile() callback and the timer to see who finishes first. If the timer finishes first, then it will call its callback and you will attempt to access data BEFORE it has been filled in (because the fs.readFile() callback has not yet been called).

You cannot write reliable code this way as you are guessing on the timing of indeterminate, asynchronous operations. Instead, you have to use the asynchronous result from within the callback because that's the only place that you know the timing for when it finished and thus when it's valid. So, one way to solve your problem is by chaining the asynchronous operations so you put the second one INSIDE the callback of the first:

function timeSeries(obj, callback) {
    //read file named as passed object's _id
    fs.readFile("./api/assignment_data/" + obj._id + ".json", "utf-8", function read(err, datas) {
        if (err) {
            console.log(err);
            // tell caller about our error
            callback(err)
            return;
        } else {
            let data = [{original_value: []}];
        
            const filedata = JSON.parse(datas);
            for (let line of filedata) {
                data[0].original_value.push(line.original_value);
            }

            fs.writeFile("./api/timeseries.json", JSON.stringify(data), { encoding: 'utf8' }, (err) => {
                if (err) {
                    console.log(err);
                    callback(err);
                    return;
                } else {
                    // give our data to the caller
                    callback(data);
                }
            });
        }
    })
}

Then, to call this function, you pass it a callback and in the callback you can either see the error or get the data.


In modern nodejs, it's a bit easier to use async/await and the promise-based interfaces in the fs module:

const fsp = require('fs').promises;

async function timeSeries(obj) {
    //read file named as passed object's _id
    try {
        let datas = await fsp.readFile("./api/assignment_data/" + obj._id + ".json", "utf-8");
        const filedata = JSON.parse(datas);
        let data = [{original_value: []}];

        for (let line of filedata) {
            data[0].original_value.push(line.original_value);
        }

        await fsp.writeFile("./api/timeseries.json", JSON.stringify(data), { encoding: 'utf8' });
        return data;
    } catch(e) {
        console.log(e);
        // handle error here or throw back to the caller
        throw e;
    }
}

For this version, the caller can use await and try/catch to get errors:

try {
    let data = await timeSeries(obj);
    // do something with data here
} catch(e) {
    // handle error here
}
about 4 years ago · Juan Pablo Isaza Relatório

0

Based on what code you have written , I could just modify it using simple async-await - hope this helps

import fs from 'fs'
async function timeSeries(obj) {
    const data = [{
        original_value: []
    }]
    const assData = fs.readFileSync('./api/assignment_data/metrics.json', 'utf8')
    const filedata = JSON.parse(assData)
    filedata.map(line => data[0].original_value.push(line.original_value))
    // no need for timeOut 
    fs.writeFileSync('./api/timeseries.json', JSON.stringify(data));
    //return data if u need
    return data
}

router.route("/api/debug/:num").get(async (req, res) => {
        try {
            const metricData = fs.readFileSync('./api/assignment_data/metrics.json', 'utf8')

            const objdata = JSON.parse(data)

            const timeSeriesData = await timeSeries(objdata[req.params.num])
            // returning TimeSeriesData
            res.status(200).json(timeSeriesData)
        })
}
catch (error) {
    res.status(500).send(error.message)
}
        
about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda