How to access variables within closures in Javascript [duplicate] - javascript

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 6 years ago.
I am creating a weather app using Node.js to access the current weather.
When I call the openweatherapp API, the temperature variable retrieved through the JSON that I am trying to pass on to module.exports is nested within a series of closure functions.
Is there any way for me to access the temperature and pass it through module.exports so I can retrieve the data from another file?
var http = require('http')
const apiKey = "myAPIkey"
// Connect to API URL api.openweathermap.org/data/2.5/weather?q={city name}
function accessWeather(city, callback) {
var options = {
host: "api.openweathermap.org",
path: "/data/2.5/weather?q=" + city + "&appid=" + apiKey + "",
method: "GET"
}
var body = ""
var request = http.request(options, function(response) {
response.on('data', function(chunk) {
body += chunk.toString('utf8')
})
response.on('end', function() {
var json = JSON.parse(body)
var temperature = parseInt(json["main"]["temp"] - 273)
})
})
request.end()
}
temp = accessWeather("Calgary")
console.log(temp)
module.exports = {
accessWeather: accessWeather
}

Well here we have a misconception of how async works in JavaScript. You can't return data that are going to be loaded in the future.
There are few options to solve this.
1 ) Export a function that takes another function as a parameter and call that function when you resolve your data :
module.export = function accessWeather(city, callback) {
var options = {
host: "api.openweathermap.org",
path: "/data/2.5/weather?q=" + city + "&appid=" + apiKey + "",
method: "GET"
}
var body = ""
var request = http.request(options, function(response) {
response.on('data', function(chunk) {
body += chunk.toString('utf8')
})
response.on('end', function() {
var json = JSON.parse(body)
var temperature = parseInt(json["main"]["temp"] - 273);
callback(temperature);
})
})
request.end()
}
2 ) Because the callback style is legacy now, you can do something even better with Promises.
module.export = function accessWeather(city, callback) {
return new Promise(function(resolve, reject){
var options = {
host: "api.openweathermap.org",
path: "/data/2.5/weather?q=" + city + "&appid=" + apiKey + "",
method: "GET"
}
var body = ""
var request = http.request(options, function(response) {
response.on('data', function(chunk) {
body += chunk.toString('utf8')
})
response.on('end', function() {
var json = JSON.parse(body)
var temperature = parseInt(json["main"]["temp"] - 273);
resolve(temperature);
})
})
request.end()
});
}
You can use also ESNext features like Generators and what I prefer even more if using Observables.

Related

How to fetch email thread by messageId using IMAP in NodeJS?

I want to fetch whole reply thread using the particular messageId something like this 2a2b0f84-261c-ecd5-33bf-919548b76000#hotmail.com.
I have tried this:
const getInbox = () => {
return new Promise((resolve, reject) => {
imaps.connect(config).then(function (connection) {
return connection.openBox('INBOX').then(function () {
var searchCriteria = ['ALL'];
var fetchOptions = {
bodies: ['HEADER', 'TEXT', ''],
};
return connection.search(searchCriteria, fetchOptions).then(async function (messages) {
let promises = messages.map(item=>{
return new Promise((resolve,reject)=>{
var all = _.find(item.parts, { "which": "" })
var id = item.attributes.uid;
var idHeader = "Imap-Id: " + id + "\r\n";
simpleParser(idHeader + all.body, (err, mail) => {
resolve(mail);
});
});
});
Promise.all(promises).then(data=>{
let d = data.filter(obj=>obj.me).map(obj=>{
return {
from:obj.from.value.map(obj=>obj.address).join(','),
to:obj.to.value.map(obj=>obj.address).join(','),
subject:obj.subject,
attachments:obj.attachments,
message_id:obj.messageId,
date:obj.date
}
});
resolve(d);
})
});
});
});
}); }
I have tried this , it is returning whole inbox, I want particular message thread.
I tried this
var searchCriteria = [['HEADER','IN-REPLY-TO',messageId]];
it is working perfectly.
This line in your code means to search for all messages:
var searchCriteria = ['ALL'];
Really quite clear code, don't you agree? If you try something more like
var searchCriteria = ['OR HEADER "Message-ID" "' + id + '" HEADER "References" "' + id + '"'];
then you'll search for just the messages you want, and then you can retrieve their headers and bodies and do whatever you want.

CallbackHandler in Node.js

I have the following method in a .js file for an asynchronous network connection
function requestWatsonDiscovery(queryString) {
console.log('Query =', queryString);
if (typeof queryString !== 'undefined') {
var discoveryUrl = `something`
console.log('Total url =', discoveryUrl);
var options = {
host: 'gateway.watsonplatform.net',
path: discoveryUrl,
auth: auth
};
http.get(options, function(http_res) {
// initialize the container for our data
var data = "";
// this event fires many times, each time collecting another piece of the response
http_res.on("data", function(chunk) {
// append this chunk to our growing `data` var
//console.log(data);
data += chunk;
});
// this event fires *one* time, after all the `data` events/chunks have been gathered
http_res.on("end", function() {
// you can use res.send instead of console.log to output via express
//console.log(data);
data = JSON.parse(data);
watsonReturnedText = parseData(data);
//console.log(watsonReturnedText);
//returnResult();
});
});
}
}
at the same time I am updating my UI in another .js file.I want to get notified when the above asynchronous method has completed. I understand I can use callbacks /promises to do it.Can you show me the syntax to write a promise or a call back.
Simply put, this should give you basic understanding of callback in your demo
function requestWatsonDiscovery (queryString, callback){ // <- new param
http.get(options, function (http_res) {
var data = "";
http_res.on("data", function (chunk) {
data += chunk;
});
http_res.on("end", function () {
var parseData =JSON.parse(data);
callback(parseData); // <- usage of new param
});
});
}
requestWatsonDiscovery(null, function(result) {
// result is your data;
console.log(result);
});
This is basically..
function requestWatsonDiscovery (queryString){
return new RSVP.promise((resolve, reject) => {
if (typeof queryString !== 'undefined') {
var discoveryUrl = `something`
var options = {
host: 'gateway.watsonplatform.net',
path: discoveryUrl,
auth : auth
};
http.get(options, function (http_res) {
var data = "";
http_res.on("data", function (chunk) {
data += chunk;
});
http_res.on("end", function () {
data =JSON.parse(data);
watsonReturnedText = parseData(data);
resolve(watsonReturnedText);
});
});
}
else { reject(); }
}); //end promise
}
When you call your requestWatsonDiscovery do this...
var watsonPromise = requestWatsonDiscovery(queryString);
watsonPromise.then((data) => {
//use your watson data
}).catch(() => {
//manage the error
});

Javascript callback function not work

I'm working with nodeJS and expressJS. I Have 2 functions,
main functions:
download(imgUrl, imgMD5, function(fileLength, fileSize) {
console.log(fileLength);
var qb = data.Img.query();
qb.where('img_md5', '=', imgMD5).update({
img_downloaded: 1
}).then(function() {});
});
and external function
module.exports = function() {
return function(uri, filename) {
request(uri, function(err, res, callback) {
fileLength = res.headers['content-length'];
var mkdirs = function(fold, callback) {
var pf = path.dirname(fold);
fs.exists(pf, function(exists) {
var create = function() {
fs.mkdir(fold, callback);
};
if (exists) {
create();
} else
mkdirs(pf, create);
})
};
var folder = ('./downloaded/' + yy + '/' + mm + '/' + dd + '/' + ho + '/');
mkdirs(folder, function() {
var r = request(uri).pipe(fs.createWriteStream(folder + filename));
r.on('close');
});
callback(fileLength);
});
};
};
but it's fired an error when running:
TypeError: string is not a function
I don't know if I'm uses the callback right or not?
thank you
Your request() callback parameters aren't quite labelled appropriately. The third argument passed to your callback is the entire buffered (string) body from the response, not a function. So that's why it complains at callback(fileLength);.
Also, because you used a callback (which receives the entire buffered response), there is no need to request the URL again. So you could change this:
mkdirs(folder, function(){
var r = request(uri).pipe(fs.createWriteStream(folder + filename));
r.on('close');
});
to this:
mkdirs(folder, function() {
// `data` here is the third argument to the `request()` callback ...
fs.writeFile(folder + filename, data);
});
to save an extra HTTP request.
Or if you really do want to stream the response data, you could do:
request(uri).on('response', function(res) {
// ...
mkdirs(folder, function() {
res.pipe(fs.createWriteStream(folder + filename));
});
});

Pass a variable to a function from another function in JavaScript (winJs)

Hi I'am working with Windows 8 app using Java Script
function fetchFromLiveProvider(currentList, globalList,value) {
feedburnerUrl = currentList.url,
feedUrl = "http://ajax.googleapis.com/ajax/services/feed/load?v=1.0&output=json&num=999&q=" + encodeURIComponent(feedburnerUrl);
WinJS.xhr({url: feedUrl, responseType: "rss/json"
}).done(function complete(result) {
var jsonData = JSON.parse(result.response);
//console.log(JSON.stringify(jsonData));
var entries = jsonData.responseData.feed;
});
}
function setOther(entries){
//some code here
}
I want to do is pass the entries in the fetchFromLiveProvider function to another function called setOther(entries){}. Thank you for any help...
Since WinJS.xhr returns a promise, you can do the following:
var entriesPromise = function fetchFromLiveProvider(currentList, globalList, value) {
feedburnerUrl = currentList.url,
feedUrl = "http://ajax.googleapis.com/ajax/services/feed/load?v=1.0&output=json&num=999&q=" + encodeURIComponent(feedburnerUrl);
return WinJS.xhr({
url: feedUrl,
responseType: "rss/json"
});
}
function setOther(entries) {
entries.done(function complete(result) {
var jsonData = JSON.parse(result.response);
//console.log(JSON.stringify(jsonData));
var entries = jsonData.responseData.feed;
//some code here
})
}
setOther(entriesPromise);

NodeJS return http.request

Hi now I know that NodeJS is asynchronous (which I am still trying to get my head around to be honest).
The problem that I am currently facing is I have attempting to do a http.request to receive some JSON data. This is fine but what I need is to return this data to a variable. I believe I need to do a callback function? (from what I have read up on the matter)
The Code that I currently have:
var http = require('http');
pCLatLng = '';
function postCodeCheck() {
var pCode = {
host: 'geo.jamiethompson.co.uk',
path: "/" + 'SW1A2AA' + ".json"
};
http.request(pCode).on('response', function(response) {
var data = '';
response.on("data", function (chunk) {
data += chunk;
});
response.on('end', function () {
pCJSON = JSON.parse(data);
pCLatLng = pCJSON;
});
}).end();
}
console.log(pCLatLng);
This is obviously outputting "undefined"; I have tried returning the response.on('end') when having return "hi" or anything inside it instead NodeJS outputs the information about the site. If anyone can help with this it would be much appreciated.
console.log(pCLatLng); needs to be inside (or inside something called by) the response.on('end' callback. The value isn't available until that callback is fired.
Try something like:
function postCodeCheck(callback) {
var pCode = {
host: 'geo.jamiethompson.co.uk',
path: "/" + 'SW1A2AA' + ".json"
};
http.request(pCode).on('response', function(response) {
var data = '';
response.on("data", function (chunk) {
data += chunk;
});
response.on('end', function () {
callback(JSON.parse(data));
});
}).end();
}
postCodeCheck(function (pCLatLng)
{
console.log(pCLatLng);
});
You want something like this:
var http = require('http');
function postCodeCheck(cb) {
var pCode = {
host: 'geo.jamiethompson.co.uk',
path: "/" + 'SW1A2AA' + ".json"
};
http.request(pCode).on('response', function(response) {
var data = '';
response.on("data", function (chunk) {
data += chunk;
});
response.on('end', function () {
var pCJSON = JSON.parse(data);
cb(pCJSON);
});
}).end();
}
postCodeCheck(function(pCLatLng) { console.log(pCLatLng); });
Look carefully for the differences before using.
You'll need your postCodeCheck() function to take a callback as well, just like http.request. In the world of async, calling callbacks with results takes a similar role to returning results.

Categories

Resources