【问题标题】:Node js lost in asynchronous behaviour: undefinedNode js 在异步行为中丢失:未定义
【发布时间】:2023-04-08 22:23:01
【问题描述】:

目标

免责声明:我是节点世界的新手,很难理解节点异步行为。

我正在尝试编写一个包装函数来对给定的 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. res.on(end) 块上返回 parsedData
  2. 定义var 并复制parsedData
  3. 复制到全局变量(虽然我知道这是非常糟糕的做法)

我查过的地方

  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

更新:工作代码

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);
});

【问题讨论】:

    标签: javascript json node.js asynchronous get


    【解决方案1】:

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

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

    更长的答案:Javascript(和结果是 Node)是一种单线程语言,它使用回调作为将异步结果返回给被调用者的机制。为此,您将一个函数作为 参数 传递给异步函数,然后该函数在将来某个时间点被调用,只要异步函数准备好发回它的结果。从这个“匿名函数”调用return 实际上只是从您发送到异步函数的“回调”函数返回。

    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)
    })
    

    【讨论】:

    • 你可能想传递getJson()一个url。
    • @PseudoAj Javascript 是一门很酷的语言,我会看一些关于该语言如何工作的资料:stackoverflow.com/questions/21607692/…
    • 谢谢@tommybananas 会调查的
    【解决方案2】:

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

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

    如果你把你的console.log() 放在res.on('end) 里面就可以了。如果将所有逻辑放在res.on('end) 中,您需要处理这个问题的方式,或者将回调传递给您在res.on('end') 中调用的getJson() 函数,或者将所有内容包装在一个promise 中,这你可以从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

    【讨论】:

      【解决方案3】:

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

      你可以用 promise 模式修复它。

      试试这样的:

      /**
       * 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 完成。

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

      【讨论】:

        【解决方案4】:

        我认为输出是正确的。getJson(myUrl) 是返回 undefined,因为您没有在 getJson 函数中设置 return,默认情况下是 javascript return undefined

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

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

        【讨论】:

        • 虽然我在示例中没有return 声明,正如我在尝试过的事情中提到的那样;包括退货没有帮助。
        • 我的意思是,如果同步线程中没有返回,那么默认返回 undefined 。
        猜你喜欢
        • 1970-01-01
        • 2017-08-25
        • 2017-12-09
        • 1970-01-01
        • 1970-01-01
        • 2015-07-24
        • 1970-01-01
        • 1970-01-01
        • 2018-05-15
        相关资源
        最近更新 更多