Retrieve data from request.end() in node.js - javascript

I want to use result of unirest request to another file in Node.js but I can not get data from request.end() function to outer variable.
Code is below:
request.end(function (response) {
if(response.error) {
console.log("AUTHENTICATION ERROR: ", response.error);
} else {
callback(null, response.body);
}
console.log("AUTHENTICATION BODY: ", response.body);
});
var result = authentication(function(error, response) {
var authenticationToken = response.access_token;
if(authenticationToken != null) {
console.log("Token: ", authenticationToken);
return authenticationToken;
}
});
I want to get authenticationToken value to export with module.exports for another modules.
I am using unirest http library.

its a callback function, and is treated as parameter, not a function that returns value.
You can do this though:
var result;
authentication(function(error, response) {
var authenticationToken = response.access_token;
if(authenticationToken != null) {
console.log("Token: ", authenticationToken);
module.exports.result = authenticationToken; // setting value of result, instead of passing it back
}
});
you can use result variable now.
But be careful, its an asynchronous function, so you may not be able to use it immediately, until a value is assigned to it, within a callback function.
To export result value:
module.exports.result = null;
Example
m1.js
setTimeout(() => {
module.exports.result = 0;
}, 0);
module.exports.result = null;
app.js
const m1 = require('./m1.js');
console.log(JSON.stringify(m1));
setTimeout(() => {
console.log(JSON.stringify(m1));
}, 10);
Output
{"result":null}
{"result":0}
so you can keep using variable result, once the variable is assigned it would contain the value.

Related

Access value that promise .then returns outside of promise

Title says it all, I am using the async-library eachSeries method
let
valueOne = null,
validItem = null;
const asyncEachSeries = require('async/eachSeries');
const getContent = function (item) {
contentResponse = fetchContent(item);
return contentResponse;
}
if (recommendationsArr.length > 0) {
asyncEachSeries(recommendationsArr, function (item, callback) {
getApiContent(item).then(function getValidResult(response) {
try {
valueOne = response.content.valueOne || null; //may or may not be present
recommendationsArr.splice(recommendationsArr.indexOf(item), 1);
validItem = item;
console.log("##### valueOne is: ", valueOne); // I get data here
return true;
} catch (err) {
valueOne = null;
return false;
}
});
//I am guessing I need a return statement here, though not sure what
});
console.log("##### Outside promise, valueOne is: ", valueOne); // no data here
// Access valueOne, validItem, recommendationsArr to be able to pass as props for the component
return {
component: <Layout><ComponentName
//pass other non-dependent props
validItem={validItem}
valueOne={valueOne}
recommendationsArr={recommendationsArr}
/></Layout>,
title: `Page Title`,
};
}
return null;
Scenario: recommendationsArr is an array of items (Its 99.9% not null, but since its an external api call I prefer to have a check). The purpose is to have values for valueOne, validItem, and an updated recommendationsArr.
The validity depends on the existence of valueOne, so if the recommendationsArr[0] has valid valueOne then I don't need to fetch api results for the rest of the array. I am using eachSeries as it runs only a single async operation at a time, hence if that async gets me the valid result I don't have to iterate over other items.
Sample recommendationsArr: recommendationsArr = ["blue", "white", "green", "red"]; //usually the array is anywhere between 12-50 elements
Now in order to be able to pass the updated values to the component I need to be able to access the values set in try block outside of the asyncEachSeries iteration loop. I understand I will have to return the processed/new values but am not sure at what point and how to return those values.
As is usual with any question concerning asynchronous code you return values by using the callback. But eachSeries does not collect return values. What you want is async.mapSeries:
async.mapSeries(recommendationsArr, function (item, callback) {
getApiContent(item).then(function (response) {
try {
valueOne = response.content.valueOne || null; //may or may not be present
recommendationsArr.splice(recommendationsArr.indexOf(item), 1);
validItem = item;
callback(null, valueOne); // This is how you return a value
// return true; // return does absolutely nothing
} catch (err) {
valueOne = null;
callback(err, valueOne);
// return false;
}
});
},function (err, result) {
// this is where you can process the result
// note that the result is an array
});
However, since you are using promises you can use async-q instead which wraps caolan's async library in promises:
var asyncQ = require('async-q');
asyncQ.mapSeries(recommendationsArr, function (item) {
// Note: the return in the line below is important
return getApiContent(item).then(function (response) {
try {
valueOne = response.content.valueOne || null; //may or may not be present
recommendationsArr.splice(recommendationsArr.indexOf(item), 1);
validItem = item;
return valueOne; // this is how you return a value in a promise
} catch (err) {
return null
}
});
})
.then(function(result) {
// you can process the result here
});
Personally I'd prefer to rewrite the code and process the results at the end because the code is cleaner:
asyncQ.mapSeries(recommendationsArr, getApiContent)
.then(function (result) {
for(var i=0;i<result.length;i++) {
var response = result[i];
// do what needs to be done with each response here
}
});

how to return meteor call value in helper in meteor

I have pass id to helper from html and my helper is getusername
getusername(id) {
var username = "";
Meteor.call("getUserName", id, function(error, result) {
if (error) {
console.log("error", error);
}
if (result) {
console.log(result);
username = result;
}
});
return username;
}
while i log the result its log what i need but in UI no username visible.
and when i use this with Reactive var its become infinity ... because when reactive variable value change its execute again...
You cannot asynchronously fetch data and return it from the same helper, because the helper returns before the call is complete and there is no reactive variable to indicate that the data has changed once the call is complete. You are right about using ReactiveVar, but to avoid infinite loop you must run Meteor.call outside the template helper. I'd recommend doing it in the template's onCreated hook:
Template.x.onCreated(function() {
var self = this;
Meteor.call("getUserName", this.data.id, function(error, result) {
if (result) {
self.username = new ReactiveVar(result);
}
});
});
Template.x.helpers({
getUserName(id) {
return Template.instance().username.get();
}
});
Note, however, that in almost all cases it's better to do things like fetching an user's name directly in the front-end like return Meteor.users.findOne(id).profile.name or something, as this is reactive and easier.
because of async behavior you wont get the return value what you can do is set the return value in session and get it from session where ever you want
getusername(id) {
var username = "";
Meteor.call("getUserName", id, function(error, result) {
if (error) {
console.log("error", error);
}
if (result) {
console.log(result);
username = result;
}
});
Session.set('getUserNameResult', result);
}

Callbacks within http request methods - not happening in correct order

I've written a program that makes an HTTP GET request for three distinct URLs. The program is supposed to output the message body in the order the URLs are provided, however it's not doing so even though I'm making callbacks in exactly that order.
The final program is supposed to require the user to input the URLs via command line, however I've simply made variable assignments for ease of testing.
I realize this code could be more object-oriented - however I'm new to JavaScript and it's not my focus to learn how at the moment
var http = require('http')
// var url_1 = process.argv[2]
// var url_2 = process.argv[3]
// var url_3 = process.argv[4]
var url_1 = 'http://youvegotmail.warnerbros.com/cmp/0frameset.html'
var url_2 = 'http://www.3riversstadium.com/index2.html'
var url_3 = 'http://toastytech.com/evil/'
var output_1 = ''
var output_2 = ''
var output_3 = ''
function getHttp_1 (callback) {
http.get(url_1, function getResponse (response1) {
response1.setEncoding('utf8')
response1.on('data', function (data) {
output_1 = output_1 + data
})
response1.on('end', function processData() {
console.log("Printing Result 1:")
callback(output_1)
})
})
}
function getHttp_2 (callback) {
http.get(url_2, function getResponse (response2) {
response2.setEncoding('utf8')
response2.on('data', function (data) {
output_2 = output_2 + data
})
response2.on('end', function processData() {
console.log("Printing Result 2:")
callback(output_2)
})
})
}
function getHttp_3 (callback) {
http.get(url_3, function getResponse (response3) {
response3.setEncoding('utf8')
response3.on('data', function (data) {
output_3 = output_3 + data
})
response3.on('end', function processData() {
console.log("Printing Result 3:")
callback(output_3)
})
})
}
function printResults(output) {
console.log("Result")
// console.log(output)
}
getHttp_1(printResults)
getHttp_2(printResults)
getHttp_3(printResults)
EDIT:
Results I'm generally getting:
Printing Result 3:
Result
Printing Result 2:
Result
Printing Result 1:
Result
Results I'm expecting:
Printing Result 1:
Result
Printing Result 2:
Result
Printing Result 3:
Result
In contrast to the sequential callback approach proposed by some answers, using Promises will make this both more efficient (the requests will be made in parallel) and simpler:
var http = require('http'),
urls = [
'http://youvegotmail.warnerbros.com/cmp/0frameset.html',
'http://www.3riversstadium.com/index2.html',
'http://toastytech.com/evil/'
];
Promise.all(urls.map(getUrl))
.then(function (results) {
results.forEach(function (output, i) {
console.log("Result #" + (i + 1) +
" with length: " + output.length);
});
});
function getUrl(url, i) {
return new Promise(function (resolve, reject) {
http.get(url, function getResponse(resp) {
var output = '';
resp.setEncoding('utf8');
resp.on('data', function (data) {
output += data;
});
resp.on('end', function processData() {
console.log("Resolving Result " + (i + 1) + ":");
resolve(output);
});
})
});
}
Welcome to the asynchronous life of node.js! As you fire off those HTTP requests, one will not wait for the request before it to finish before it fires. You are seeing this odd behavior because you are practically sending all 3 requests at once, and simply printing as you see the responses.
Edit: If you do want to see them in correct order, fire off the second HTTP request inside the callback of the first, and then the third inside the callback of the second. That guarantees you won't get the data until after each one before it finishes.
function getHttp_1 (callback) {
http.get(url_1, function getResponse (response1) {
response1.setEncoding('utf8')
response1.on('data', function (data) {
output_1 = output_1 + data
})
response1.on('end', function processData() {
console.log("Printing Result 1:")
callback(output_1)
getHttp_2(callback)
})
})
}
The async module can really help for controlling how async tasks are executed. For example, if you want your requests to happen one after the other:
async.series([
function (next) { makeRequest(url_1, next); },
function (next) { makeRequest(url_2, next); },
function (next) { makeRequest(url_3, next); },
], function (err, result) {
// All done
});
// Or you can get fancy
//async.series([
// makeRequest.bind(null, url_1),
// makeRequest.bind(null, url_2),
// makeRequest.bind(null, url_3),
//]);
function makeRequest(url, callback) {
http.get(url, function getResponse (res) {
var output = '';
res.setEncoding('utf8')
res.on('data', function (data) {
output += data
})
response1.on('end', function processData() {
callback(output)
})
})
}
If you don't care what order they occur in but want to output them in order:
async.parallel([
function (next) { makeRequest(url_1, next); },
function (next) { makeRequest(url_2, next); },
function (next) { makeRequest(url_3, next); },
], function (err, results) {
if (err) {
return void console.error('Got an error:', err.stack);
}
console.log(results); // Will output array of every result in order
});
If the requests are dependent on each other, async.auto is useful to tie the result of one request to the request of another.
JavaScript/AJAX calls are async so don't follow the order you call them. To call them in sequence/specific order, do like:
$(function () {
//setup an array of AJAX options, each object is an index that will specify information for a single AJAX request
var ajaxes = [{ url : '<url>', dataType : 'json' }, { url : '<url2>', dataType : 'utf8' }],
current = 0;
//declare your function to run AJAX requests
function do_ajax() {
//check to make sure there are more requests to make
if (current < ajaxes.length) {
//make the AJAX request with the given data from the `ajaxes` array of objects
$.ajax({
url : ajaxes[current].url,
dataType : ajaxes[current].dataType,
success : function (serverResponse) {
...
//increment the `current` counter and recursively call this function again
current++;
do_ajax();
}
});
}
}
//run the AJAX function for the first time once `document.ready` fires
do_ajax();
});
Another option could be:
function callA() {
$.ajax({
...
success: function() {
//do stuff
callB();
}
});
}
function callB() {
$.ajax({
...
success: function() {
//do stuff
callC();
}
});
}
function callC() {
$.ajax({
...
});
}
callA();
Ref: Multiple Calls in Order

Callback problems

I am new into javascript, and currently I'm trying to learning callback to my script. This script should return reduced words in array of objects
var fs = require('fs')
var dict = ['corpus.txt','corpus1.txt','corpus2.txt'];
mapping(dict, function(error,data){
if(error) throw error
console.log(data)
})
function mapping(list, callback){
var txtObj = []
list.forEach(function (val) {
readFile(val, function(error,data){
txtObj.push(data)
})
})
function readFile(src, cb){
fs.readFile(src,'utf8', function (error,data) {
if (error) return callback(error,null)
return mapred(data)
})
}
return callback(null,txtObj)
}
But it returns empty array. Any help would be appreciated.
Thanks!
`fs.readFile`
is an asynchronous function, before it's done and result callback is invoked, you are returning the empty txtObj array.
how to fix it ?
call return callback(null,txtObj) after fs.readFile is finished running.
and also, as you are running asynchronous function on an array of items one-by-one, it might not still work the way you want. might want to use modudles like async in nodejs
Here comes an asynchronous version using module async. synchronous file operation is strongly objected :)
var fs = require('fs')
var dict = ['corpus.txt','corpus1.txt','corpus2.txt'];
mapping(dict, function(error,data){
if(error) throw error
console.log(data)
})
function mapping(list, callback){
var txtObj = [],
async = require('async');
async.each(list, readFile, function(err) {
callback(err,txtObj)
});
function readFile(src, cb) {
fs.readFile(src,'utf8', function (error,data) {
if (error) {
cb(error);
}
else {
txtObj.push(mapred(data));
cb(null);
}
})
}
}
EDIT : You can do this without async, but it is little bit dirty isn't it ? also its OK if you remove the self invoking function inside the forEach, i included so that you can access the val, even after the callback is done
var fs = require('fs')
var dict = ['corpus.txt','corpus1.txt','corpus2.txt'];
mapping(dict, function(error,data){
if(error) throw error
console.log(data)
})
function mapping(list, callback){
var txtObj = [],
counter = list.length,
start = 0;
list.forEach(function (val) {
(function(val)
readFile(val, function(error,data) {
txtObj.push(data);
start++;
if(error || (start === counter)) {
callback(error,txtObj);
}
}))(val);
})
function readFile(src, cb) {
fs.readFile(src,'utf8', function (error,data) {
if (error) {
cb(error);
}
else {
txtObj.push(mapred(data));
cb(null);
}
})
}
}
The reason you are getting an empty array result is that you are performing the callback before the readFile function has a chance to populate the array. You are performing multiple asynchronous actions but not letting them to complete before continuing.
If there was only one async action, you would call callback() in the callback function of readFile, but as you need to perform multiple async actions before calling callback(), you should consider using fs.readFileSync().
Sometimes sync cannot be avoided.
function mapping(list, callback)
{
var txtObj = []
list.forEach(function(val)
{
try { txtObj.push(mapred(fs.readFileSync(val, 'utf8'))) }
catch(err) { callback(err) }
})
callback(null, txtObj)
}

Callback on node.js http REST call issue

Have a following node.js call to http get REST API. When I run it, it returns the JSON result. However, I am trying to get the result to console.log on var r after assigning the result. Why do I always get undefined? Looks like I am messing up the javascript scope. Any help is appreciated.
var http = require('http'),
oex_appId = 'myappId',
_hostname = 'openexchangerates.org',
_path = '/api/latest.json?app_id=' + oex_appId;
var r;
function getRates(cb) {
var options = {
hostname: _hostname,
path: _path,
method: 'GET'
};
var responseCallback = function(response) {
var latestRates = '';
var parseCurrencies = function(rates) {
var currencies = JSON.parse(rates);
currencies.rates['USD'] = 1;
return currencies.rates;
};
response.setEncoding('utf8');
response.on('data', function(chunk) {
latestRates += chunk;
}).on('error', function(err) {
throw new Error(err);
}).on('end', function() {
cb(parseCurrencies(latestRates));
});
};
var req = http.request(options, responseCallback);
req.on('error', function(e) {
throw e;
});
req.end();
};
var d = function(data) {
console.log(data["INR"]);
currencies["INR"].amount = data["INR"];
r = data;
};
getRates(d);
console.log(r);
Why do I always get undefined?
Your problem is not an scope issue but a misunderstanding of async execution. In this code you are printing the value of r before it is assigned.
The execution of your code is as follow:
getRates() is called
console.log(r) is called (hence you get undefined)
When the request executed in getRates finishes your callback is THEN executed. This is when you are assigning a value to r but by then is too late since you already printed it.
In general, you cannot expect the next line to have a value that will be assigned via an async callback. Instead you should reference the value inside the callback. In your case you should move the console.log(r) inside your callback function d.

Categories