Javascript multiple promises not working with q and request middle - javascript

So this is my dilemma. I have a list of movies, witch I have scraped from a website, then I want to add additional properties to my newly constructed object(json)
Now the omdi api witch I am using supports searching for a movie by title.
Then I make a get request using request and q middlewares. When I receive information from omdb api in the call back I add that data to the object.
Now the next part is where my problem lies. Now I want to return a new Request using data from the previous request. Now I make an new get Request and return it but then() func isin't returning anything. But I don't seem to realize what I am doing wrong.
Here is my code..
var promises = [];
films.forEach(function (film) {
// Get omdbapi information
promises.push(HttpService.getContent(configExternal.omodburl + '?t=' + film.title.trim() + '&y=' + film.year + '&plot=true&tomatoes=true&r=json').then(function (data) {
var result = JSON.parse(data);
if(Boolean(result.Response) === true) {
film.omdb.push(result);
}
var imdbid = result.imdbID;
return HttpService.getContent(configExternal.themoviedburl + imdbid + '/videos?api_key=' + configExternal.themoviedbkey);
}).then(function(data) {
film.trailers = [];
film.trailers.push(JSON.parse(data));
}).catch(function (err) {
logger.error().info('Error getting ' + film.title + ' from omdb, ErrorMessage : ' + err);
}));
});
//--------------------------------
// When all promises have finished
//--------------------------------
Promise.all(promises).then(function (data, err) {
// do stuff with the data
});
And here is my getContent func
var Service = {
getContent: function(url) {
var deferred = q.defer();
request(url, function (error, response, body) {
if (!error && response.statusCode == 200) {
deferred.resolve(body);
} else {
deferred.reject(error);
}
});
return deferred.promise;
}
};

Problem solved. There wasn't anything wrong with the request as Roamer said. But the moviedata base limits by 40 request per 10 sek witch I didn't know :)

Related

Ajax call inside forEach loop Angular

I am having an Array that contains objects in AngularJS. Based on the value of a property (snooz) of these objects I have to call a POST request (getData.sonnzeUpdate()). After going through each object in the array, finally, I have to call a GET request. My issue is the GET request (inside the function $scope.getTableData) is executed before getting the response (res in .then(function(res){}) of the POST request.
I have tried with angular.forEach() and $q.
Here is my code sample
var notifiedAlarms = [];
var d = new Date();
var checkTine = d.getHours() + "-" + d.getMinutes() + "-" + "00";
angular.forEach(snoozedData, function (snoozed_asset, asset_key) {
if (snoozed_asset.snooz == checkTine) {
var data = {};
snoozed_asset.snooz = '';
data.data = snoozed_asset;
var deferred = $q.defer();
getData.sonnzeUpdate(data).then(function (res) {
if (res.status == '200') {
toastr.info('Alarm with property ' + data.data.actualFailureArea + ' is activated');
// $scope.getTableData(); //donot want to call it here. as same call will for multiple time
notifiedAlarms.push(deferred.promise);
} else {
// console.log('Error in update');
}
});
} else {
// no matching snooz
}
});
$q.all(notifiedAlarms).then($scope.getTableData());
In your code, notifiedAlarms is empty at that point: $q.all(notifiedAlarms), because you add the promises to that Array, after they have finished.
And avoid the Deferred antipattern. getData.sonnzeUpdate() already returns you a Promise.
angular.forEach(snoozedData, function (snoozed_asset, asset_key) {
if (snoozed_asset.snooz != checkTine) return;
snoozed_asset.snooz = '';
notifiedAlarms.push(
getData.sonnzeUpdate({ data: snoozed_asset }).then(function(res) {
if (res.status == '200') {
toastr.info('Alarm with property ' + data.data.actualFailureArea + ' is activated');
} else {
throw new Error('Error in update');
}
})
);
});
With $q.all(notifiedAlarms).then($scope.getTableData()) you're executing $scope.getTableData() directly instead of telling it to call it once promises are resolved. Hence, it gets executed earlier than you want.
Change it to $q.all(notifiedAlarms).then($scope.getTableData); to get desired behavior.
Here's an example elaborating this:
jsfiddle example
Notice how in the fiddle, I have both ways,
myownservice.UpdateSomeData().then($scope.setValue)
myownservice.UpdateSomeData().then($scope.setValue2())
And, in HTML only value gets updated and not value2

NodeJS Promises: Proper way to combine multiple HTTP requests returns

Have a NodeJS process that reaches out to a webservice for something called Kudos. These kudos are sent from one person to another person/or group of people. What I'm trying to do is create one message that has the following:
Kudos from {poster} to {receiver/s}
{Kudos Message}
Currently I have the process working correctly for poster to one receiver. I am struggling with making it work with getting the multiple names of the receivers.
The problem stems from the fact that the section where it returns the users receiving the kudos, it only provides the user id. So I need to make another call to obtain the user's name. I can easily get the promises to work for the one user, but I can seem to get the multiple user properly.
The JSON data that contains the multiple users looks something like this:
"notes_user": [
{
"id": "1060",
"note_id": "795",
"user_id": "411"
},
{
"id": "1061",
"note_id": "795",
"user_id": "250"
},
{
"id": "1062",
"note_id": "795",
"user_id": "321"
}
],
Here is the function that does the majority of the work:
getMaxId returns a database index of that highest kudos currently processed, and getKudos just returns the json dataset of "kudos".
function promisifiedKudos() {
var maxid;
var newmaxid;
Promise.all([getMaxId(), getKudos()])
.then(function(results) {
maxid = results[0];
var kudos = results[1];
newmaxid = kudos[0].id;
return kudos.filter(function(kudo) {
if (maxid < kudo.id) {
return kudo;
}
})
})
.each(function(kudo) {
return getTribeUserName(kudo);
})
.then(function(results) {
return results.map(function(kudo) {
var message = "Kudos from " + kudo.poster.full_name + " to " + kudo.kudo_receiver_full_name + "\r\n";
message += "\r\n";
return message += entities.decode(striptags(kudo.note));
})
})
.each(function(message) {
return postStatus(message);
})
.then(function() {
var tribehr = db.get('tribehr');
console.log(new Date().toString() + ":Max ID:" + newmaxid);
tribehr.update({ endpoint: "kudos" }, { $set: { id: newmaxid } });
})
.done(function(errors) {
console.log("Run Complete!");
return "Done";
});
}
The helper function getTribeUserName()
function getTribeUserName(kudo) {
return new Promise(function(fulfill, reject) {
var id = kudo.notes_user[0].user_id;
var options = {
url: "https://APIURL.com/users/" + id + ".json",
method: "GET",
headers: {
"Authorization": "Basic " + new Buffer("AUTHCODE" + AUTHKEY).toString('base64')
}
}
request.getAsync(options).then(function(response) {
if (response) {
var data = JSON.parse(response.body)
kudo.kudo_receiver_full_name = data.User.full_name;
fulfill(kudo);
} else {
reject("Get Tribe User Name Failed");
}
});
});
}
I've tried adding a helper function that calls the getTribeUserName() that looks like this:
function getTribeUsers(kudo) {
return new Promise(function(fulfill, reject) {
kudo.notes_user.map(function(user) {
//Make calls to a getTribeUserName
})
});
}
But the outcome is that the user names are undefined when the finalized message is put together.
Any pointers in how to use promises better would be extremely helpful. This is really my first stab with them and I hope I'm heading in the right direction. I know I need to add the error checking in, but currently I'm just trying to get the process working for multiple users.
if you need to use the result of a promise passed as parameter of the resolve function then you can catch it in the then onFulfilled callback.
If you need to pass some data obtained within a then method of a chain to another then you just have to return it and catch it through the onFulfilled callback of the following then.
object.somePromise().then(function(param){
var data = someFunction();
return data;
}).then(function(param){
//param holds the value of data returned by the previous then
console.log(param);
});
If it's a matter of getting multiple TribeUserNames asynchronously, then you need somehow to aggregate promises returned by multiple calls to getTribeUserNames().
You could write Promise.all(array.map(mapper)) but Bluebird provides the more convenient Promise.map(array, mapper).
Bluebird's .spread() is also convenient, for referencing maxid and kudos.
Here it is in as simple a form as I can manage :
function promisifiedKudos() {
return Promise.all([getMaxId(), getKudos()])
.spread(function(maxid, kudos) {
var newmaxid = kudos[0].id;
// The following line filters (synchronously), adds TribeUserNames (asynchronously), and delivers an array of processed kudos to the next .then().
return Promise.map(kudos.filter((kudo) => kudo.id > maxid), getTribeUserName)
.then(function(filteredKudosWithTribeUserNames) { // in practice, shorten arg name to eg `kudos_`
return Promise.map(filteredKudosWithTribeUserNames, function(kudo) {
return postStatus("Kudos from " + kudo.poster.full_name + " to " + kudo.kudo_receiver_full_name + "\r\n\r\n" + entities.decode(striptags(kudo.note)));
});
})
.then(function() {
var tribehr = db.get('tribehr');
console.log(new Date().toString() + ":Max ID:" + newmaxid);
return tribehr.update({ endpoint: 'kudos' }, { $set: { 'id': newmaxid } });
});
})
.then(function() {
console.log('Run Complete!');
}).catch(function(error) {
console.log(error);
throw error;
});
}
getTribeUserName() needs to return a promise, and can be written as follows :
function getTribeUserName(kudo) {
var options = {
'url': 'https://APIURL.com/users/' + kudo.notes_user[0].user_id + '.json',
'method': 'GET',
'headers': {
'Authorization': 'Basic ' + new Buffer('AUTHCODE' + AUTHKEY).toString('base64')
}
}
return request.getAsync(options).then(function(response) {
// ^^^^^^
if(response) {
kudo.kudo_receiver_full_name = JSON.parse(response.body).User.full_name;
} else {
throw new Error(); // to be caught immediately below.
}
return kudo;
}).catch(function(error) { // error resistance
kudo.kudo_receiver_full_name = 'unknown';
return kudo;
});
}
Further notes:
By nesting Promise.map(...).then(...).then(...) in the .spread() callback, newmaxid remains available through closure, avoiding the need for an ugly outer var.
Promise.map() is used a second time on the assumption that postStatus() is asynchronous. If that's not so, the code will still work, though it could be written slightly differently.

wait for request to finish and return data

I'm building an Restful API with node js this is my code
There are 3 main parts, I created a get method that has to return some data
the get calls getImportIoData that has a request to an external API and this method calls another method called getEmailFromWebSite this other method calls another request,
how can I wait for every request to finish an return data
I Know this has been answered in other questions but I tried some of them and didn't work
I tried Async and q libraries, also the callback on this part Doesn't work
if (item.website !== undefined){
getEmailFromWebSite(item.website, function(email){console.log(email); item.email = email;});
}
I don't know If Im doing something wrong,
Can someone help me with this? using my code
Thanks in advance
router.get('/', function(req, res) {
var Type = req.query.Type;
var Locations = req.query.Locations;
var Page = req.query.Page;
res.send(getImportIoData(res, Type, Locations, Page));
});
function getImportIoData(res, Type, Locations, Page) {
var criteria = {
'search_terms': Type,
'geo_location_terms': Locations,
'page': Page
}
var url = consts.import_io + consts.import_key + consts.query +
encodeURIComponent(consts.api_url) + encodeQueryData(criteria) +
/*"&_user=" + consts.user + */"&_apikey=" + consts.api_key;
request(url, function(error, response, json) {
var data = JSON.parse(json);
if (!error && response.statusCode === 200) {
var doctors = _.forEach(data.results, function(item) {
if (item.website !== undefined){
getEmailFromWebSite(item.website, function(email){console.log(email); item.email = email;});
}
});
return data.results
}
//else
});
}
function getEmailFromWebSite(website, callback) {
var EmptyReturn='';
searchTerm = extractDomain(website).replace('www.', '');
if (searchTerm != ''){
var EH_APIURL = 'https://api.emailhunter.co/v1/search?domain='+searchTerm+'&api_key='+ consts.EmailHunterAPIKey;
request(EH_APIURL, function(error, response, json) {
var data = JSON.parse(json);
if (!error && response.statusCode === 200) {
if((data.emails).length != 0){
var Emailobject = data.emails;
var EmailString = returnEmails(Emailobject);
callback(EmailString);
}else
callback(EmptyReturn);
}else if (response.statusCode === 429)
console.log('The number of Request has been Reached for this account');
else if (response.statusCode > 500)
console.log('Error with Email Hunter Servers');
else
console.log('An Error Ocurred');
});
}
}
There's no code related to q in there but q.all receives an array of promises and resolves when all of those promises are resolved, so you can do something like this..
var promises = [ promiseOne(), promiseTwo(), promiseThree() ];
q.all(promises).then(function(results) {
//results is an array with the resolution values from all your promises in the order you specified in the promises array
});

How to chain two ajax requests with promises

I am having trouble with ajax/promises. I have two ajax requests total, with the second ajax call relying data to be returned by the first ajax call.
My first ajax call finds Latitude, Longitude, and country code of the value of #search.
My second ajax call finds the weather of that city, but the API URL is dependent on the Latitude, Longitude and country code that my first ajax call returns. So the second ajax call can't be started until the first one is finished.
My logic here is that var ajax1 is assigned a promise, and var ajax2 starts after ajax1.then() checks that ajax1's promise is resolved. Then ajax2 runs and returns another promise. Finally ajax2.done starts after it checks that ajax2's promise is resolved, and then starting my successWeatherFunction().
My problem is that ajax2.done is not working, as the console.log("test") is not showing up on the console. The two earlier console.logs, console.log(info) and console.log(weatherApiUrl) are working.
Thanks!
$("#search").keypress(function(event) {
if (event.which === 13) {
var searchCity = $("#search").val();
var jsonURL = "http://autocomplete.wunderground.com/aq?query=" + searchCity + "&cb=?"
var ajax1 = $.getJSON(jsonURL);
var ajax2 = ajax1.then(function(data) {
var info = [];
info.push(data["RESULTS"][0]["name"]);
info.push(data["RESULTS"][0]["c"]);
info.push(data["RESULTS"][0]["lat"]);
info.push(data["RESULTS"][0]["lon"]);
console.log(info);
var searchLat = info[2];
var searchLng = info[3];
var countryCode = info[1];
if (countryCode === "US") {
var weatherApiUrl = "https://api.forecast.io/forecast/{APIKEY}/" + searchLat + "," + searchLng + "?exclude=minutely" + "&callback=?";
} else {
var weatherApiUrl = "https://api.forecast.io/forecast/{APIKEY}/" + searchLat + "," + searchLng + "?exclude=minutely" + "?units=si" + "&callback=?";
console.log(weatherApiUrl);
}
return $.getJSON(weatherApiUrl);
});
ajax2.done(function(data){
console.log("test");
successCityWeather(data);
});
Your code use then and done. done is the old promises jQuery syntax so you should use only then.
The following code works for me :
$(function() {
$.get('/test').then(function() {
console.log('First request end');
return $.get('/test');
}).then(function() {
console.log('second request end');
});
});
But in your case, maybe a one of your request fail. Give a second parameter to then to log the error :
$.getJSON('...').then(function(data) {
console.log('success', data);
}, function(data) {
console.log('fail', data);
});
If not sure, always use always() handler. That way you will know if the request actually finished with error or not at all.
$.ajax( ...params... )
.always(function(jqXHR, textStatus) {
if (textStatus != "success") {
alert("Error: " + jqXHR.statusText); //error is always called .statusText
} else {
alert("Success: " + jqXHR.response); //might not always be named .response
}});
$.post(jsonURL)
.then(function (data) {
var info = [];
// some actions
return $.getJSON(weatherApiUrl);
})
.then(function(data, status, promise) {
// some actions
successCityWeather(data);
})

"undefined is not a function" using callbacks

I'm creating a twitter bot that is requesting from the same API, Wordnik, but each request is depending on the last request's results. So, I decided to try creating some code using callbacks to make sure that all of the information is returned from the API before the next function runs. I am having trouble setting it up, I have looked at many examples and I just cannot get the hang of it. (Sorry for the messy code).
The error I am getting right now is "undefined is not a function" in my function getWord() on thenRunThisFunction(getRhyme). I'm wondering if I have a small error with the callbacks or if my whole approach to this problem is incorrect?
function runBot() {
var request = require('request');
var Twit = require('twit');
var async = require('async');
var T = new Twit({
consumer_key: '' // Your Consumer Key
, consumer_secret: '' // Your Consumer Secret
, access_token: '' // Your Access Token
, access_token_secret: '' // Your Access Token Secret
});
var WORDNIKAPIKEY = '';
// GLOBAL VARS
var randomWord; //get random word
var rhymingWord; //get rhyming word
var bogusDef; //get def of rhyming word
var tweet; // combined random and bogusdef
function getWord(thenRunThisFunction){
request('http://api.wordnik.com:80/v4/words.json/randomWord?hasDictionaryDef=false&minCorpusCount=0&maxCorpusCount=-1&minDictionaryCount=1&maxDictionaryCount=-1&minLength=5&maxLength=-1&api_key=' + WORDNIKAPIKEY, function (error, response, body1) {
if (!error && response.statusCode == 200) {
//console.log(body1) // Show the HTML for the Google homepage.
var pparsedData = JSON.parse(body1);
console.log("Word: " + pparsedData.word);
// set random word
randomWord = pparsedData.word;
thenRunThisFunction(getRhyme);
}
})
}
// Get the rhyming word
function getRhyme(thenRunThisFunction){
request('http://api.wordnik.com:80/v4/word.json/' + randomWord + '/relatedWords?useCanonical=false&relationshipTypes=rhyme&limitPerRelationshipType=10&api_key=' + WORDNIKAPIKEY, function (error, response, body2) {
if (!error && response.statusCode == 200) {
//console.log(body2) // Show the HTML for the Google homepage.
var o = JSON.parse(body2);
console.log("Rhyme: " + o[0].words[0]);
// set rhyming word
rhymingWord = o[0].words[0];
thenRunThisFunction(getDef);
}
})
}
// GET THE SEXY DEFINITION BABY, BEACH BOD
function getDef(thenRunThisFunction){
request('http://api.wordnik.com:80/v4/word.json/' + rhymingWord + '/definitions?limit=200&includeRelated=true&sourceDictionaries=all&useCanonical=false&includeTags=false&api_key=' + WORDNIKAPIKEY, function (error, response, body3) {
if (!error && response.statusCode == 200) {
//console.log(body3) // Show the HTML for the Google homepage.
var newnew = JSON.parse(body3);
console.log("Definition: " + newnew[0].text);
// set definition
bogusDef = newnew[0].text;
randomWord = randomWord.charAt(0).toUpperCase();
tweet = randomWord + ": " + bogusDef;
thenRunThisFunction(postStatus);
}
})
}
function postStatus(){
T.post('statuses/update', { status: tweet }, function(err, data, response) {
if(err) {
console.log("There was a problem tweeting the message.", err);
}
});
console.log("status posted");
}
getWord();
}
runBot();
You are not passing a function reference into getWord().
I have no clue really what you're trying to accomplish, instead of going
thenRunThisFunction();
thenRunThisFunction();
thenRunThisFunction();
thenRunThisFunction();
thenRunThisFunction();
Just invoke them by their names, remove the argument from them
getRhyme();
getDef();
What you're doing will never work, you're trying to call thenRunThisFunction as if it actually exists, it's an argument in your function that never gets served
Your method would work if it was like this:
function runThisFunction(fnc) {
fnc();
}
function blah(thenRunThisFunction) {
thenRunThisFunction(thing);
}
function thing() {
console.log('Blah');
}
blah(runThisFunction);
But that's horrible and bad.
You aren't passing anything to getWord at the end so thenRunThisFunction is literally undefined. Try passing a function to getWord like this getWord(function(){}). But in your case you want to pass whatever you want to run after get word.

Categories