Calling async functions recursively - javascript

I need to have an async method eg. getWeather called forever with a small delay between the success of previous call and beginning of the next call. I have used a recursive function for the purpose. I am concerned if this can cause a performance hit. Are there any better ways to do this?
var request = require('request');
var Promise = require('bluebird');
var delayTwoSecs = function() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve();
}, 2000);
});
};
var getWeather = function() {
return new Promise(function(resolve, reject) {
request({
method: 'GET',
uri: 'http://api.openweathermap.org/data/2.5/weather?lat=35&lon=139'
}, function(error, response, body) {
if (error) {
reject(error);
} else {
resolve(body)
}
});
});
};
var loopFetching = function() {
getWeather()
.then(function(response) {
console.log(response);
return delayTwoSecs();
}).then(function(response) {
loopFetching();
});
};
loopFetching();

You don't need the delayTwoSecs function, you can use the Promise.delay function.
Instead of getWeather, you can use the bluebird to Promisify all the functions and use the proper function, in this case getAsync, directly.
So, your program becomes like this
var Promise = require('bluebird');
var request = Promise.promisifyAll(require('request'));
var url = 'http://api.openweathermap.org/data/2.5/weather?lat=35&lon=139';
(function loopFetching() {
request.getAsync(url)
// We get the first element from the response array with `.get(0)`
.get(0)
// and the `body` property with `.get("body")`
.get("body")
.then(console.log.bind(console))
.delay(2000)
.then(loopFetching)
.catch(console.err.bind(console));
})();
This is called Immediately Invoking Function Expression.

setInterval() for recurring requests
You're over-complicating it with nested calls. Use setInterval() instead.
var request = require('request');
var Promise = require('bluebird');
var getWeather = function() {
return new Promise(function(resolve, reject) {
request({
method: 'GET',
uri: 'http://api.openweathermap.org/data/2.5/weather?lat=35&lon=139'
}, function(error, response, body) {
if (error) {
reject(error);
} else {
resolve(body)
}
});
});
};
var my_interval = setInterval("getWeather()",2000);

Related

Response is send immediately and does not wait for await

I want to wait for the getAllData function to be finished, but that does not work.
let _partnerToken;
async function getAllData(dealerId,id){
let partnerToken;
var options = {
'method': 'GET',
'url': _url + '/' + dealerId,
};
request.get(options, async function (error, response) {
if (error) throw new Error(error);
partnerToken = response.body.slice(17,-2);
await getCarData(partnerToken,id);
await getCarImages(partnerToken, id);
_partnerToken = partnerToken;
})
}
Here the post request where I want to call this function and send a response when the data is all loaded and the function is finished.
app.post('/api/urlData', async function(req,res){
const str = CircularJSON.stringify(req);
await getAllData(req.body.dealerId, req.body.vin);
res.send(req)
});
The problem is that it does the response immediately, so there is no data for the frontend.
My goal is to send a signal with the response to my frontend, that all the data has loaded and can then be displayed.
async functions always must return a Promise. If you don't return a Promise, the runtime implicitly creates and returns one resolving to your return value (in your case undefined).
The reason why the call to api/urlData happens immediately without waiting for the other requests to be completed in getAllData() is that you're calling request.get(...) passing a callback function. This function works asynchronously, but for the runtime it's an ordinary synchronous function call.
To solve this problem you have to create and return a Promise manually in getAllData() and call the resolve() callback after all requests have been completed:
async function getAllData(dealerId, id) {
return new Promise<any>((resolve, reject) => {
const options = {
'method': 'GET',
'url': _url + '/' + dealerId,
};
request.get(options, async function (error, response) {
if (error) {
reject(error);
return;
}
let partnerToken = response.body.slice(17,-2);
await getCarData(partnerToken,id);
await getCarImages(partnerToken, id);
_partnerToken = partnerToken;
resolve(returnValue); // <--- your return value
});
});
}
await getAllData(1, 2)
Solution
I started working with Promises and now the the responds waits for the functions to be finished.
Here is one of the new methods:
async function getCarData(partner, id) {
const options = {
url: url + '/?partnertoken=' + partner + '&fahrzeug_id=' + id,
headers: {
'x-api-key': key
}
};
return new Promise(function (resolve, reject){
request.get(options, function (error, response, body) {
if (!error && response.statusCode == 200) {
let res = JSON.parse(body);
resolve(res.data[0]);
}else
reject(error);
});
})
}
app.post('/api/urlData', async function (req, res) {
let vin = req.body.vin;
let dealerId = req.body.dealerId;
const str = CircularJSON.stringify(req);
_partnerToken = await getPartnerToken(dealerId);
_data = await getCarData(_partnerToken,vin);
_dataImage = await getCarImages(_partnerToken,vin);
res.send(str)
});
I resturctured it so that every of the three methods returns a Promise.

Repeat data redundant variable

I have two functions that I declare the same variable twice. My code works but its not the most efficient, Can someone help me restructure the code so that I may set once and use it twice rather than setting it twice.
I was thinking something like this. but its not working
var promise = new Promise(function (resolve) // repeat code
function () {
promise. { code }
Code
As you can see bellow var promise = new Promise(function (resolve) is repeated in the first and second function, I feel this is not the most efficient way of writing this.
var firstFunction = function () {
var promise = new Promise(function (resolve) {
setTimeout(function () {
app.post('/test.js', function (req, res) {
console.log(req.body);
var login = req.body.LoginEmail;
res.send(login);
resolve({
data_login_email: login
});
});
console.error("First done");
}, 2000);
});
return promise;
};
var secondFunction = function () {
var promise = new Promise(function (resolve) {
setTimeout(function () {
nodePardot.PardotAPI({
userKey: userkey,
email: emailAdmin,
password: password,
DEBUG: false
}, function (err, client) {
if (err) {
console.error("Authentication Failed", err);
} else {
var api_key = client.apiKey;
console.log("Authentication successful !", api_key);
resolve({data_api: api_key});
}
});
console.error("Second done");
}, 2000);
});
return promise;
};

Return Promise From REST Call

I'm trying to invoke a REST call and return a promise so I can manipulate the data afterwhich.
var self = this;
var returnPromise;
returnPromise = self.httpService.testService();
returnPromise.then(function(result){
console.log(result);
});
My REST service is located in another file which has the following:
testService() {
console.log("start of testService");
var request = require('request');
var user = "test";
var ipadd = "127.0.0.1";
request({
url: 'https://' + 'LocalHost' + '/URLOFWEBSERVICE',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
form: {
userID: user,
userIpAddress: ipadd
}
}, function(error, response, body) {
if (error) {
console.log(error);
} else {
console.log(response.statusCode, body);
var newPro = new Promise(function(fulfill, reject) {
fulfill(body);
});
console.log(newPro);
return newPro;
}
});
}
I'm able to print out response.stateCode , body( REST result) and the "invoked fulfill" console is printed out.
The problem lies with the
returnPromise.then
in the first page, in which ".then" returns me undefined.
At first I thought that it might be the promise has been called before the REST returns me a response. So, I thought of doing a timeout function to test.
setTimeout(
function(){
console.log(returnPromise);
}
, 5000);
But even so, returnPromise returns me "undefined".
If you expect a function to return a promise, it should return a promise
your testService does not return anything
this does:
testService() {
console.log("start of testService");
var request = require('request');
var user = "test";
var ipadd = "127.0.0.1";
return new Promise(function(fulfill, reject) {
request({
url: 'https://' + 'LocalHost' + '/URLOFWEBSERVICE',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
form: {
userID: user,
userIpAddress: ipadd
}
}, function(error, response, body) {
if (error) {
// reject the promise, handle with .catch
reject(error);
} else {
console.log(response.statusCode, body);
fulfill(body);
}
});
});
}
That can be called as
// var self = this; // why? not needed in the code shown
// var returnPromise; // why? it's not needed in the code shown
this.httpService.testService()
.then(function(result) {
console.log(result);
})
.catch(function(err) {
// handle your errors here
});

How to capture the event in which all promises in the array are resolved?

I am using Bluebird library with NodeJS (with SailsJS framework)
Promise.all() is not capturing the event when all the promises in promises array are resolved.
What changes should be made in order to solve this problem?
var Promise = require("bluebird");
var request = require('request');
var http = require('http');
function searchMultiple(titles) {
var results = [];
return new Promise( function( resolveGlobal, rejectGlobal ){
var url = "http://xxx.xxx";
var promises = [];
titles.forEach(function (title, index) {
promises[index] = new Promise( function (resolve, reject) {
var data = {"x":title};
request({
uri: url,
method: "POST",
body : data
}, function(error, response, body) {
return resolve(body)
}
}
},
function (error, response, body) {
console.log("error");
return resolve();
}
);
})
})
Promise.all(promises).then(function(combinedResults) {
console.log("successfully resolved all promises");
return resolveGlobal(combinedResults);
}).catch(function (reason) {
console.log("error");
return rejectGlobal();
});
})
}
There is no need for you to return resolve(value), as it should only resolve the with the given result value.
There's also no reason to create a new promise in your searchMultiple function, since the Promise.all returns a promise. You should just return the promise you already have!
The resolveGlobal() is thus unnecessary and you can just return the result instead, since the then will wrap it as a resolved value.
All of your code can be rewritten as two very simple functions
function searchMultiple(titles) {
//Empty array of promises
var promises = [];
var url = "http://xxx.xxx";
//Get a promise for each title and push to array
titles.forEach(function(title){
promises.push(getData(title, url));
});
//Wait for all promises to resolve, and return the result
return Promise.all(promises)
.then(function(arrayOfResults){
//If this only shall return the array, this can be omitted aswell as the catch!
return arrayOfresults;
})
.catch(function(reason){
//Handle errors
});
}
function getData(title, url){
return new Promise(function(resolve, reject){
var data = {"x":title};
request({
uri: url,
method: "POST",
body : data
}, function(error, response, body) {
resolve(body)
}
}
},
function (error, response, body) {
console.log("error");
//Consider rejecting here instead since you'll get a result that is 'undefined'
resolve();
});
});
}
You should consider rejecting the promise in the error handler instead of resolving it with an undefined value. You might end up with errors further down the road if you get a result array back that have values that are undefined.
Try this:
var Promise = require('bluebird');
var request = require('request');
function searchMultiple(titles) {
return new Promise(function (resolveGlobal, rejectGlobal) {
var url = 'http://xxx.xxx';
var promises = [];
titles.forEach(function (title) {
promises
.push(new Promise(function (resolve, reject) {
var data = {
'x': title
};
request({
uri: url,
method: 'POST',
body: data
},
function (error, response, body) {
if (!error && response.statusCode == 200) {
return resolve(body);
}
return reject(error);
});
}));
});
Promise
.all(promises)
.then(function (combinedResults) {
console.log('successfully resolved all promises');
return resolveGlobal(combinedResults);
})
.catch(function (error) {
console.log('error');
return rejectGlobal(error);
});
});
}
And call function:
searchMultiple([...])
.then(function (results) {
console.log(results);
})
.catch(function (error) {
console.log(error);
});

How to properly code a promise returning function?

I'm trying to code functions following the promise return pattern, this is a generic example of what I'm trying:
var Promise = require('bluebird');
var request = require('request');
var returnPromise = Promise.method(function () {
request
.get('http://google.com/img.png')
.on('response', function(response) {
if (response.statusCode !== 200)
throw new Error('Bad request');
else
return response.headers;
})
});
returnPromise()
.then(function (headers) {
console.log(headers);
})
.catch(function (err) {
console.log('Error handling);
});
However this is not working properly as the error is yet being thrown and not handled. How should this be implemented?
var Promise = require('bluebird');
var request = require('request');
var returnPromise = function () {
return new Promise(function(resolve, reject){
request
.get('http://google.com/img.png')
.on('response', resolve)
.on('error', reject)
});
});
You should use new Promise instead of Promise.method. This is because throwing or returning from event handlers isn't captured by the promise.
var Promise = require('bluebird');
var request = require('request');
var returnPromise = function () {
return new Promise(function(resolve, reject){
request
.get('http://google.com/img.png')
.on('response', function(response) {
if (response.statusCode !== 200)
reject(Error('Bad request'));
else
resolve(response.headers);
})
});
});
returnPromise()
.then(function (headers) {
console.log(headers);
})
.catch(function (err) {
console.log('Error handling);
});

Categories

Resources