Проблема глобальной переменной Nodejs - PullRequest
0 голосов
/ 04 ноября 2019

Я немного новичок в nodejs и заранее извиняюсь, если мне не хватает чего-то очевидного. В следующем коде я получаю данные json из API.

let data_json = ''; // global variable

app.get('/', (req, res) => {
    request('http://my-api.com/data-export.json', (error, response, body) => {
        data_json = JSON.parse(body);
        console.log( data_json ); // data prints successfully
    });

    console.log(data_json, 'Data Test - outside request code'); // no data is printed
})

data_json - моя глобальная переменная, и я присваиваю данные, возвращаемые функцией запроса. Внутри этой функции данные json печатаются просто отлично. Но я пытаюсь распечатать те же данные вне функции запроса, и ничего не печатается.

Мне нужна помощь, чтобы понять причину и исправить любую ошибку, которую я делаю, пожалуйста.

Ответы [ 2 ]

1 голос
/ 04 ноября 2019

Вместо ожидания запроса на разрешение (получения данных из вашего API) Node.js выполнит код снаружи и ничего не напечатает, потому что в момент выполнения ничего не происходит, и только после того, как узел получит данные изВаш API (который займет несколько миллисекунд) выполнит код внутри запроса. Это потому, что nodejs является асинхронным и неблокирующим языком, то есть он не будет блокировать или останавливать код до тех пор, пока ваш API не вернет данные, он просто продолжит работу и завершит работу позже, когда получит ответ.

Это хорошопопрактикуйтесь в том, чтобы делать все необходимые манипуляции с данными внутри функции обратного вызова, к сожалению, вы не можете полагаться на имеющуюся у вас структуру.

Вот пример вашего кода, только закомментированный порядок операций:

let data_json = ''; // global variable

app.get('/', (req, res) => {
    //NodeJS STARTS executing this code
    request('http://my-api.com/data-export.json', (error, response, body) => {
        //NodeJS executes this code last, after the data is loaded from the server
        data_json = JSON.parse(body);
        console.log( data_json );
        //You should do all of your data_json manipluation here
        //Eg saving stuff to the database, processing data, just usual logic ya know
    });

    //NodeJS executes this code 2nd, before your server responds with data
    //Because it doesn't want to block the entire code until it gets a response
    console.log(data_json, 'Data Test - outside request code'); 
})

Допустим, вы хотите сделать еще один запрос с данными из первого запроса - вам нужно будет сделать что-то вроде этого:

request('https://your-api.com/export-data.json', (err, res, body) => {
    request('https://your-api.com/2nd-endpoint.json', (err, res, body) => {
         //Process data and repeat
     })
    })

Как вы можете видеть, этот шаблонможет очень быстро запутаться - это называется адом обратного вызова, поэтому, чтобы избежать большого количества вложенных запросов, есть синтаксический сахар, чтобы этот код выглядел гораздо более навороченным и поддерживаемым, он называется шаблоном Async / Await. Вот как это работает:

let data_json = ''

app.get('/', async (req,res) => {
    try{
        let response = await request('https://your-api.com/endpoint')
        data_json = response.body
    } catch(error) {
        //Handle error how you see fit
    }
    console.log(data_json) //It will work
})

Этот код делает то же самое, что и тот, который у вас есть, но разница в том, что вы можете сделать столько await request(...), сколько захотите, один за другим, без вложений. Единственное отличие состоит в том, что вы должны объявить, что ваша функция асинхронная async (req, res) => {...} и что все let var = await request(...) должны быть вложены в блок try-catch. Это так, чтобы вы могли поймать свои ошибки. Вы можете иметь все свои запросы в блоке catch, если считаете, что это необходимо.

Надеюсь, это немного помогло:)

1 голос
/ 04 ноября 2019

console.log появляется перед вашим запросом, проверьте способы получения асинхронных данных: обратный вызов, обещания или async-await. API-интерфейсы Nodejs являются асинхронными (большинство из них), поэтому внешний console.log будет выполнен до того, как request вызов API завершится.

let data_json = ''; // global variable
app.get('/', (req, res) => {
    let pr = new Promise(function(resolve, reject) {

        request('http://my-api.com/data-export.json', (error, response, body) => {
            if (error) {
                reject(error)
            } else {
                data_json = JSON.parse(body);
                console.log(data_json); // data prints successfully
                resolve(data_json)
            }
        });

    })
    pr.then(function(data) {
      // data also will have data_json
      // handle response here

     console.log(data_json); // data prints successfully

    }).catch(function(err) {
        // handle error here
    })

})

Если вы не хотите создавать оболочку обещаний, вы можете использовать request-promise-native (использует собственные Обещания), созданные командой модуля «Запрос».

Learn callbacks, promises и, конечно, async-await.

...