节点js在异步行为中丢失:未定义

时间:2017-10-02 00:59:19

标签: javascript json node.js asynchronous get

目的

  

免责声明:我是节点世界的新手,并且很难绕过节点异步行为。

我正在尝试编写一个包装函数来对给定的URL执行https.get并返回json输出。

代码

const https = require('https');

// Get the user details
var myUrl = <valid-url>;

const getJson = function(url) {
  // https get request
  const req = https.get(url, (res) => {
    // get the status code
    const { statusCode } = res;
    const contentType = res.headers['content-type'];

    // check for the errors
    let error;
    if (statusCode !== 200) {
      error = new Error('Request Failed.\n' +
                        `Status Code: ${statusCode}`);
    } else if (!/^application\/json/.test(contentType)) {
      error = new Error('Invalid content-type.\n' +
                        `Expected application/json but received ${contentType}`);
    }
    if (error) {
      console.error(error.message);
      // consume response data to free up memory
      res.resume();
      return;
    }

    //parse json
    res.setEncoding('utf8');
    let rawData = '';
    res.on('data', (chunk) => { rawData += chunk; });
    res.on('end', () => {
      try {
        const parsedData = JSON.parse(rawData);
        console.log(parsedData);
      } catch (e) {
        console.error(e.message);
      }
    });
  }).on('error', (e) => {
    console.error(`Got error: ${e.message}`);
  });
}

console.log(getJson(myUrl));

输出

undefined
{ user_id: <user-id>,
  name: 'Ajay Krishna Teja',
  email: <my-email> }

问题

因此https.get能够达到终点并获取数据但无法返回json。不断返回Undefined

我尝试过的事情

  1. parsedData阻止
  2. 上返回res.on(end)
  3. 定义var并复制parsedData
  4. 复制到全局变量(虽然我知道这是非常糟糕的做法)
  5. 我抬头的地方

    1. Node.js variable declaration and scope
    2. How to get data out of a Node.js http get request
    3. Javascript function returning undefined value in node js
    4. 更新:工作代码

      const getJson = function(url,callback) {
        // https get request
        const req = https.get(url, (res) => {
          // get the status code
          const { statusCode } = res;
          const contentType = res.headers['content-type'];
      
          // check for the errors
          let error;
          if (statusCode !== 200) {
            error = new Error('Request Failed.\n' +
                              `Status Code: ${statusCode}`);
          } else if (!/^application\/json/.test(contentType)) {
            error = new Error('Invalid content-type.\n' +
                              `Expected application/json but received ${contentType}`);
          }
          if (error) {
            console.error(error.message);
            // consume response data to free up memory
            res.resume();
            return;
          }
      
          //parse json
          res.setEncoding('utf8');
          let rawData = '';
          res.on('data', (chunk) => { rawData += chunk; });
          res.on('end', () => {
            try {
              const parsedData = JSON.parse(rawData);
              callback(parsedData);
            } catch (e) {
              callback(false);
              console.error(e.message);
            }
          });
        }).on('error', (e) => {
          console.error(`Got error: ${e.message}`);
        });
      
        return req;
      }
      
      // calling
      getJson(amznProfileURL,(res) => {
        console.log(res);
      });
      

4 个答案:

答案 0 :(得分:1)

简答:您没有在getJson函数中返回任何内容,undefined是默认的Node / Javascript返回值。

function getJson(){
  callAsyncFunction(param1, param2, param3)
  // there is no return value!
}

更长的答案:Javascript(和Node作为结果)是一种使用回调的单线程语言,因为它将异步结果返回给被调用者。为此,您将函数作为参数传递给异步函数,然后只要异步函数准备好发送回它的结果,就会在将来的某个时刻调用该函数。从此&#34;匿名函数&#34;中调用return实际上只是从&#34;回调&#34;您要发送到异步功能的功能。

function getJson(){
  console.log('A')
  // request is started, but getJson continues execution!
  http.get(url, (res)=> {
    console.log('C') // by the time I'm called, 'B' has already been printed and the function has returned!
    return true // this won't return getJson! It will only return the callback function which doesn't do anything!
  })
  console.log('B')
  // end of function without return value, return undefined!
}

// Will print 'A', 'B', 'C'

有几种不同的方法可以解决这个问题。传统上一直使用回调,但Javascript本身也支持Promises,它们更易于管理,并且默认情况下在许多流行的框架中使用。

您可以通过提供自己的回调参数来实现您的回调函数,以便http.get返回时自动调用。

// define getJson with second callback parameter
const getJson = function(url, callback) {
  http.get(url, (res) => {
    if(res){
      callback(res) // result came back, send to your own callback function
    } else {
      callback(false) // request failed, send back false to signify failure
    }
  })
}

// now I can use getJson and get the result!
getJson('http://getjson.com', (res) => {
 console.log('got result!', res)
})

答案 1 :(得分:1)

这是在节点(以及一般的javascript)中克服异步函数的一个非常常见的问题。

正在发生的事情是在http请求返回任何内容之前调用了console.log(getJson(myUrl))。基本上,这样的事情不适用于异步函数。

如果您将console.log()放在res.on('end)内,它就会起作用。如果您将所有逻辑放在res.on('end)哪种糟糕的情况下,或者将回调传递给您在getJson()中调用的res.on('end')函数,或者换行,则需要处理此问题的方式承诺中的所有内容,您可以从getJson()返回。

要使用回调,您可以执行以下操作:

const getJson = function(url, callback) {
     // a bunch of code

    res.on('end', () => {
      try {
        const parsedData = JSON.parse(rawData);
        callback(null, parsedDate) // callbacks in node traditionaly pass an error as the first arg
     }
    //finish
}

你用一个函数调用它:

getJson(url, function(err, return_val) {
    if (err) // handle error
    console.log(return_val)
}

您还可以查看其他HTTP库,例如Axios,它们将返回一个没有多少工作的承诺。使用axios和类似的库,您可以简单地:

axios.get(url)
.then(response => {
    console.log(response);
  })
.catch(function (error) {
    console.log(error);
 });

这是人们使用这些库的原因之一。更多信息:https://github.com/axios/axios

答案 2 :(得分:0)

因为它以异步方式运行,所以它不会等待函数调用结束。

您可以使用承诺模式修复它。

尝试这样的事情:

/**
 * Created by bagjeongtae on 2017. 10. 2..
 */
function parseData(url) {
    return new Promise((resolve, reject) => {
        https.get(url, (res) => {
            // get the status code
            const {statusCode} = res;
            const contentType = res.headers['content-type'];

            // check for the errors
            let error;
            if (statusCode !== 200) {
                reject('Request Failed.\n' + `Status Code: ${statusCode}`);
            } else if (!/^application\/json/.test(contentType)) {
                reject('Invalid content-type.\n' +
                    `Expected application/json but received ${contentType}`);
            }
            if (error) {
                console.error(error.message);
                reject(error.messag);
            }

            res.resume();

            //parse json
            res.setEncoding('utf8');
            let rawData = '';
            res.on('data', (chunk) => {
                rawData += chunk;
            });
            res.on('end', () => {
                try {
                    const parsedData = JSON.parse(rawData);
                    console.log(parsedData);
                    resolve(parseData);
                } catch (e) {
                    console.error(e.message);
                    reject(e.messag);
                }
            });
        });
    });
};

parseData('http://www.example.com').then( result =>{
    console.log(result);
}, err => {
    console.log(err);
})

从console.log运行getJson是异步的,所以它不会等待getJson完成。

异步可以像同步一样使用。

答案 3 :(得分:-1)

我认为输出是正确的。getJson(myUrl)返回undefined,因为您未在return函数中设置getJson,javascript return undefined由默认和

{ user_id: <user-id>, name: 'Ajay Krishna Teja', email: <my-email> }

是代码中console.log(parsedData)的输出。