免责声明:我是节点世界的新手,并且很难绕过节点异步行为。
我正在尝试编写一个包装函数来对给定的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
。
parsedData
阻止res.on(end)
var
并复制parsedData
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);
});
答案 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)
的输出。