function not running in order - javascript

For some reason, in node.js, the code is not running in order. It is running the console.log(data2) before even retrieving the data from function2.
I am assuming it is because node.js runs asynchronously. However, I am not too sure how to fix it.
Thanks for all the help in advance
function function1(app){
app.post('/test', (req, res, next) => {
const url = `url1`;
request(url, function(error, response, body) {
if(!error && response.statusCode == 200) {
var data = JSON.parse(body);
var data2 = function2(data.id);
console.log(data2); //undefined
res.send(profileData);
}
});
})
}
function function2(id){
const url = `url2/${id}`;
request(url, function(error, response, body) {
if(!error && response.statusCode == 200) {
var data = JSON.parse(body);
console.log(data); //output correct data
return data;
}
});
}

function function1(app){
app.post('/test', (req, res, next) => {
const url = `url1`;
request(url, async function(error, response, body) {
if(!error && response.statusCode == 200) {
var data = JSON.parse(body);
var data2 = await function2(data.id);
console.log(data2); //undefined
res.send(profileData);
}
});
})
}
function function2(id) {
const url = `url2/${id}`;
return new Promise(function (resolve, reject) {
request(url, function(error, response, body) {
if(!error && response.statusCode == 200) {
resolve(JSON.parse(body));
} else {
reject(error);
}
});
});
}

Because you're calling function2() just before outputting console.log(data2). The latter gets executed immediately, while the former has to make a server request. Pass data2 to function2() instead and output it after you output the result from function2()
function function1(app){
app.post('/test', (req, res, next) => {
const url = `url1`;
request(url, function(error, response, body) {
if(!error && response.statusCode == 200) {
var data = JSON.parse(body);
var data2 = function2(data.id, data2);
res.send(profileData);
}
});
})
}
function function2(id, data2){
const url = `url2/${id}`;
request(url, function(error, response, body) {
if(!error && response.statusCode == 200) {
var data = JSON.parse(body);
console.log(data); //output correct data
console.log(data2); //undefined
return data;
}
});
}

Related

Unable to initiate the route from the beginning after else statement deadend

Firstly, I'm sorry if this has been posted before. I searched but couldn't find any credible solution.
So I'm working on this route in nodejs where I make an API call for a piece of information and then using that info in an if statement to check if it's the correct info(the server sometimes sends wrong info).
If I get the correct info then I use that in another API to get more info about it and render it into my template. Everything works fine.
But I want the first API call to take place again if the info doesn't match or it's wrong. How can I initiate the API call again from the start(like a loop) and it will break only if the info is correct. Please check the "comment" in the code below. That is where I don't know what to put. Your help would be highly appreciated.
PS. I am a beginner in nodejs and javascript.
Route
router.get("/check", (req, res) => {
if(req.query.search) {
var input = req.query.search;
var url = "http://firstapi.com/json/" + input + "?fields=query";
request(url, function(error, response, body) {
if(!error && response.statusCode === 200) {
var data = JSON.parse(body);
if(data.query.match(/((^|\.)((25[0-5])|(2[0-4]\d)|(1\d\d)|([1-9]?\d))){4}$/)){
var url = "https://secondapi.com/" + data.query + "?key=something";
request(url, function(error, response, body) {
if(!error && response.statusCode === 200) {
var Data = JSON.parse(body);
res.render("index", {data: Data});
}
});
}else{
//want to use the input at the top and check the firstapi again. All the code above should run again until its the correct one which I will use in my template.
}
}
});
}else{
res.render("index", {data: null});
}
});
I would probably do it this way:
router.get('/check', (req, res) => {
if (req.query.search) {
var input = req.query.search;
// Put this logic away in a `checkData` function
checkData(input)
.then(data => {
res.render('index', { data }); // Short version of {data: data}
})
.catch(err => {
console.error(err);
res.render('index', { data: null });
});
} else {
res.render('index', { data: null });
}
});
// Here, we have a `retries` parameter, set to 0 initially
function checkData (input, retries = 0) {
const maxRetries = 3;
// Return a promise (you could also use callbacks)
return new Promise((resolve, reject) => {
// Define a retry method
const retry = () => {
if (retries < maxRetries) {
// Increment the retries count and go for another try
checkData(input, retries + 1).then(resolve).catch(reject);
} else {
reject(`Could not get the data after ${retries} retries.`);
}
};
var url = `http://firstapi.com/json/${input}?fields=query`;
request(url, function (error, response, body) {
if (!error && response.statusCode === 200) {
var data = JSON.parse(body);
if (data.query.match(/((^|\.)((25[0-5])|(2[0-4]\d)|(1\d\d)|([1-9]?\d))){4}$/)) {
var url = 'https://secondapi.com/' + data.query + '?key=something';
request(url, function (error, response, body) {
if (!error && response.statusCode === 200) {
var Data = JSON.parse(body);
// If it worked, resolve with the data
resolve(Data);
} else {
retry();
}
});
} else {
retry();
}
}
});
});
}

How to return value from a function to use it and respone it in router in Nodejs?

I am trying to get result from function getWeather() in Nodejs to respone it to json in one router but I can not get it.
var request = require('request');
var publicIp = require('public-ip');
function getCity (userip){
var url = `https://ipinfo.io/${userip}/json`;
request(url, (err, respone, body)=>{
var data = JSON.parse(body);
var city = data['city'];
return getLocationKey(city);
})
}
function getLocationKey(city){
var url = `http://dataservice.accuweather.com/locations/v1/cities/search?q=${city}&apikey=${API_KEY}`;
request(url, (err, respone, body)=>{
var data = JSON.parse(body);
var key = data[0].Key;
return getWeather(key);
})
}
function getWeather(key){
var url = `http://dataservice.accuweather.com/forecasts/v1/daily/1day/${key}?apikey=${API_KEY}`;
request(url, (err, respone, body)=>{
var weather = JSON.parse(body);
console.log("weather: " + weather);
return weather;
})
}
I have got result from getCity() and getLocationKey(), but when get final result from getWeather() is not successfull.
I console.log weather is Object object. I try to sepate it and call it only, it respone for me weatherDetails as images
router.get('/weather-weather', (req, res)=>{
var city = 'hanoi';
var key = '353412'
var url = `http://dataservice.accuweather.com/forecasts/v1/daily/1day/${key}?apikey=${API_KEY}`;
request(url, (err, respone, body)=>{
var weatherDetails = JSON.parse(body);
res.json(weatherDetails);
})
})
However, I want to call it in this route to respone a json but it fail
router.get('/weather', (req, res)=>{
publicIp.v4()
.then(userip=>{
console.log("userIP: " + userip);
getCity(userip);
})
.catch(err=>{
console.log('Error: '+ err);
})
})
But it failed. I don't know how to return respone result from getWeather() function. How I can get it?
The function getXXX cannot get the "return" inside the callback function.
And you did not call res.json to send the result to the client.
You could pass res to getXXX and use it in this way:
function getCity(userip, res) {
var url = `https://ipinfo.io/${userip}/json`;
request(url, (err, respone, body) => {
var data = JSON.parse(body);
var city = data['city'];
return getLocationKey(city, res);
})
}
function getLocationKey(city, res) {
var url = `http://dataservice.accuweather.com/locations/v1/cities/search?q=${city}&apikey=${API_KEY}`;
request(url, (err, respone, body) => {
var data = JSON.parse(body);
var key = data[0].Key;
return getWeather(key, res);
})
}
function getWeather(key, res) {
var url = `http://dataservice.accuweather.com/forecasts/v1/daily/1day/${key}?apikey=${API_KEY}`;
request(url, (err, respone, body) => {
var weather = JSON.parse(body);
console.log("weather: " + weather);
res.json(weather);
})
}
router.get('/weather', (req, res) => {
publicIp.v4()
.then(userip => {
getCity(userip, res);
})
.catch(err => {
console.log('Error: ' + err);
})
})

node.js: deasync never returning

In node.js I'm using deasync to return the result of a request query.
var request = require('request');
var deasync = require("deasync");
const URL_1 = "...", URL_2 = "...", USER_AGENT = "...";
function getHtml() {
function requrl(url, form) {
return {
url: url,
headers: {'User-Agent': USER_AGENT},
form: form,
jar: true
}
}
var form = {email:"email#geemail.com", password:"thepass"};
var resp;
request.post(requrl(URL_1, form), function (error, response, body) {
if (error || response.statusCode != 200) {
resp = error;
} else {
request(requrl(URL_2), function (error, response, body) {
console.log(response); // <- this makes it work
if (error || response.statusCode != 200)
resp = error;
else
resp = body;
})
}
})
while (resp === undefined) deasync.runLoopOnce();
return resp;
}
This works fine. But if i remove this line: console.log(response); it never returns. I have no idea what is going on.

Error myFunction(...).then is not a function

I have the following module that basically performs a GET request to Google:
// my-module.js
var request = require('request');
var BPromise = require('bluebird');
module.exports = get;
function get() {
return BPromise.promisify(doRequest);
}
function doRequest(callback) {
request.get({
uri: "http://google.com",
}, function (err, res, body) {
if (!err && res.statusCode == 200) {
callback(null, body);
}
else {
callback(err, null);
}
});
}
And I want to use this module like so:
//use-module.js
var myModule = require('./my-module');
myModule().then(function (body) {
console.log(body);
});
The error I'm facing is the following:
myModule(...).then is not a function.
What am I doing wrong?
BPromise.promisify(doRequest) does not call doRequest, but returns a "promisified" version of that function. You should do that once, not at each call. This should work:
module.exports = BPromise.promisify(doRequest);

NodeJS: creating a hash and return the value of a function

I have a list of tags that I need to extract. the list is called list.
I'm trying to find all 'og:*' meta that correspond to the list and are available in a fetched html. Then I need to return a hash to the user in JSON that contains these meta tags. But the process method return undefined rather than the hash.
var http = require('http');
var url = require('url');
var request = require('request');
var jsdom = require("jsdom");
var fs = require('fs');
var cssom = require('cssom');
var list = ['title', 'description']; //here the og-tags I need to extract
var meta = {};
function process(url) {
request(url, function (error, response, body) {
if (!error && response.statusCode == 200) {
jsdom.env({
html: body,
scripts: [
'http://code.jquery.com/jquery-1.5.min.js'
],
done: function(errors, window) {
var $ = window.$;
$('meta[property^="og:"]').each(function() {
for (var element in list) {
if ($(this).attr('property') == 'og:' + list[element]) {
meta[list[element]] = $(this).attr('content');
// this works well, if I do console.log(meta), I get the hash correctly filled.
}
}
});
}
});
}
});
return meta; // this is where the probleme is. This return undefined.
}
http.createServer(function (request, response) {
request.setEncoding('utf8');
response.writeHead(200, {'Content-Type': 'text/plain'});
process(url.parse(request.url, true).query['content'], function(result) {
console.log(result); // prints no result
});
response.end();
}).listen(8124);
console.log('Server running at http://0.0.0.0:8124');
Because request is asynchronous, you need to make process asynchronous as well. That means having process accept a callback parameter that it will call once meta is available. As it is now, process is returning meta before the request callback populates it.
function process(url, callback) {
request(url, function (error, response, body) {
if (!error && response.statusCode == 200) {
jsdom.env({
html: body,
scripts: [
'http://code.jquery.com/jquery-1.5.min.js'
],
done: function(errors, window) {
var $ = window.$;
$('meta[property^="og:"]').each(function() {
for (var element in list) {
if ($(this).attr('property') == 'og:' + list[element]) {
meta[list[element]] = $(this).attr('content');
callback(null, meta);
}
}
});
}
});
} else {
callback(error);
}
});
}
http.createServer(function (request, response) {
request.setEncoding('utf8');
response.writeHead(200, {'Content-Type': 'text/plain'});
process(url.parse(request.url, true).query['content'], function(error, result) {
console.log(result); // prints no result
});
response.end();
}).listen(8124);

Categories