I have an array of users who I'll loop through to get their twitch information. I have two api calls: get_channel_info1 and get_status_info1. get_channel_info1 gets the name and logo and check if accounts exist. Then depending on the account status, I want to make a second api to see if they are online or not. I created get_info to make sequential calls for one user, but now I want to use this method in a loop.
I guessing the loop doesn't isn't waiting for the api calls in the get_info to finish before continuing through the loop. I'm not sure how to overcome this problem. Could anyone help me with this?
function get_channel_info1(user) {
console.log(user);
return $.getJSON("https://" + user,function(data) {
if (data.status == null) {
twitch_channel.display_name = data.display_name;
twitch_channel.logo = data.logo;
twtich_channel.status = 200;
} else if (data.status == 404) {
twitch_channel.display_name = "User " + user + " doesn't exist";
twitch_channel.logo = "#";
twitch_channel.status = 404;
}
})
}
function get_status_info1(user) {
console.log("getting the status of " + user)
console.log(user)
return $.getJSON("https://" + user.display_name, function(data) {
if (data.stream != null) {
twitch_channel.status_title = data.stream.channel.status;
twitch_channel.status = "Online";
} else{
twitch_channel.status_title = "Null";
twitch_channel.status = "Offline";
}
})
}
function get_info(user) {
twitch_channel = {};
$.when(get_channel_info1(user)).then(function() { return get_status_info1(twitch_channel, user)} )
.then( function() { console.log(twitch_channel })
};
for (var i = 0; i < twitch_list.length; i++) {
console.log("in the for loop, calling " + twitch_list[i])
get_info(twitch_list[i]);
}
Related
I have a question. I created the following functions:
function checkGender(canidate, callback) {
var query = "SELECT a.* FROM (SELECT Id AS GebruikerId, TIMESTAMPDIFF(year, profiel_Geboortedatum, NOW()) AS Leeftijd FROM " +
"gebruikers WHERE Id = " + canidate.MedereizigerId + ") a INNER JOIN gebruikers ON gebruikers.Id = " + canidate.GebruikerId + " WHERE a.Leeftijd >= gebruikers.medereiziger_MinLeeftijd AND " +
"a.Leeftijd <= gebruikers.medereiziger_MaxLeeftijd GROUP BY a.GebruikerId;";
FYSCloud.API.queryDatabase(query).done(function (data) {
if (data.length == 1) {
callback(data);
}
else {
callback(null);
}
}).fail(function (reason) {
console.log(reason);
callback(null);
});
}
function checkAge(canidate, callback) {
var query = "SELECT a.* FROM (SELECT Id AS GebruikerId, TIMESTAMPDIFF(year, profiel_Geboortedatum, NOW()) AS Leeftijd FROM " +
"gebruikers WHERE Id = " + canidate.MedereizigerId + ") a INNER JOIN gebruikers ON gebruikers.Id = " + canidate.GebruikerId + " WHERE a.Leeftijd >= gebruikers.medereiziger_MinLeeftijd AND " +
"a.Leeftijd <= gebruikers.medereiziger_MaxLeeftijd GROUP BY a.GebruikerId;";
FYSCloud.API.queryDatabase(query).done(function (data) {
if (data.length == 1) {
callback(data);
}
else {
callback(null);
}
}).fail(function (reason) {
console.log(reason);
callback(null);
});
}
[...]
Now the queries are working like a charm but I am using the following code to call these functions:
for(var i=0; i<data.length; i++) {
// CHECK GESLACHT
checkGender(data[i], function(genderData) {
if(genderData != null) {
// CHECK LEEFTIJD
checkAge(data[i], function(ageData) {
if(ageData != null) {
// CHECK BUDGET
checkBudget(data[i], function(budgetData) {
if(budgetData != null) {
// CHECK VAKANTIELAND
checkDestinationCountries(data[i], function(destinationCountryData) {
if(destinationCountryData != null) {
// CHECK GESPROKEN TALEN
checkSpokenLanguages(data[i], function(spokenLanguagesData) {
if(spokenLanguagesData != null) {
}
});
}
});
}
});
}
});
}
});
}
What I am doing here is waiting for the function to finish and then continue with the next one, but only if the result of the function didn't return null. Now this takes up a lot of lines and tabs, so I was wondering if there was a beter way to ask everytime for a null value?
Please let me know, just out of curiosity
You can change your function to a Promise based result, instead of calling callbacks use resolve and reject, like this:
function checkAge(canidate) {
// create a new Promise and return it
return new Promise((resolve, reject) => {
var query = "SELECT a.* FROM (SELECT Id AS GebruikerId, TIMESTAMPDIFF(year, profiel_Geboortedatum, NOW()) AS Leeftijd FROM " +
"gebruikers WHERE Id = " + canidate.MedereizigerId + ") a INNER JOIN gebruikers ON gebruikers.Id = " + canidate.GebruikerId + " WHERE a.Leeftijd >= gebruikers.medereiziger_MinLeeftijd AND " +
"a.Leeftijd <= gebruikers.medereiziger_MaxLeeftijd GROUP BY a.GebruikerId;";
FYSCloud.API.queryDatabase(query).done(function (data) {
if (data.length == 1) {
resolve(data); // when successful, resolve with data
}
else {
reject('no data found'); // any error, call reject()
}
}).fail(function (reason) {
console.log(reason);
reject(reason); // any error, call reject()
});
});
}
With this, you can use async/await feature to write a generic validation method with all others validation functions, because any call to reject will throw a exception:
async function checkData(data) {
try {
const genderData = await checkGender(data);
const ageData = await checkAge(data);
const budgetData = await checkBudget(data);
const destinationCountryData = await checkDestinationCountries(data);
} catch (e) {
// some validation failed
}
}
You can use the && operator to check for a falsy value (null, 0, false, undefined, etc.) before executing a function.
value && functionCall(value)
That might make it a bit cleaner.
checkGender(data[i], genderData => genderData &&
checkAge(data[i], ageData => ageData &&
checkBudget(data[i], budgetData => budgetData &&
checkDestinationCountries(data[i], destinationCountryData => destinationCountryData &&
checkSpokenLanguages(data[i], spokenLanguagesData => spokenLanguagesData && console.log("It Works"))))))
Hi I have a for loop in my node js application which calls an async function. I want to check a value and decide whether a customer is found or not. But the loop iterates until the last element. Hence my error loop is not working. I want the loop to check the response and then iterate the next loop.
for loop:
for (let i = 0; i < customerlookupresponse.data.length; i++) {
var customer = customerlookupresponse.data[i];
if (customer != undefined) {
console.log("customer.id :: " + customer.id)
var accountlookUpData = {
customerId: customer.id
};
customerAccountLookUpRequest(accountlookUpData).then(data => {
console.log("----" + i + " -- " + data);
if (data && data.status === 1) {
resolve(data);
return;
}else{
reject({
status: 404,
message: "Customer not found"
});
return;
}
});
} else {
reject({
status: 404,
message: "Customer not found"
});
return;
}
}
the async function:
async function customerAccountLookUpRequest(customerLookUpData) {
var accountLookUp = config.app.url;
let data = await axios.get(accountLookUp).then(accountLookUpResult => {
for (i = 0; i < accountLookUpResult.data.length; i++) {
var requestaccount = accountLookUpResult.data[i].accountNumber;
if (requestaccount == customerLookUpData.lookupAccount) {
accountLookUpResult.data[i].customerId = customerLookUpData.customerId;
accountLookUpResult.data[i].status = 1;
return accountLookUpResult.data[i];
}
}
});
return data;
}
I am new to node js and trying to understand the concept of async await. Please help.
An async function waits for a Promise to return. The function that has the loop should be declared as async and the customerAccountLookUpRequest function should return a promise. Then use the await operator to call the function. Simple example:
class some_class {
constructor() {
}
async my_loop() {
let _self = this;
for (let i = 0; i < customerlookupresponse.data.length; i++) {
let data = await _self.customerAccountLookUpRequest(accountlookUpData);
console.log("----" + i + " -- " + data);
}
}
customerAccountLookUpRequest(customerLookUpData) {
return new Promise((resolve, reject) => {
axios.get(accountLookUp).then(accountLookUpResult => {
resolve(accountLookUpResult);
});
});
}
}
So, I'm using the github APIv3 to get some data for a project I'm doing. I have to be sure that the results from my request are tight cause it's for an article I'm writing on code smells.
I have to know which classes developers are messing with so my data needs to be perfect and verifiable.
I made this HTTP request to the github API to get the data. The problem is sometimes the data gathered is A, sometimes it is B. Is there a way I can be SURE the data gathered is the full and complete data that can be gathered from the API? (the errors in the console are always the same).
for (let i = 0; i < devInfo.length; i++) {
let dev = devInfo[i];
let project = dev.project;
let name = dev.dev;
let repo = reposData.find(e => e.repo == project);
let maxDate = repo.maxDate;
let url = `repos/${repo.owner}/${project}/commits`;
console.log("Dev: " + name + " Project: " + project);
client.get(url, {
until: maxDate,
author: name
}, function(
err,
status,
body,
headers
) {
if (err != null) {
console.log(err);
}
if (Array.isArray(body)) {
body.forEach(commitInfo => {
let date = new Date(commitInfo.commit.author.date);
if (commitInfo.author != null) {
client.get(`${url}/${commitInfo.sha}`, {}, function(
err,
status,
body,
headers
) {
if (err != null) {
console.log(err);
}
if (body != null || body != undefined) {
if (Array.isArray(body.files)) {
body.files.forEach(file => {
let fnArr = file.filename.split("/");
let javaClass = fnArr.find(e => e.match(/.java/));
if (validPojects.some(e => e == project)) {
if (javaClass != null) {
let classArr = javaClass.split(".");
let className = classArr[0];
fs.appendFileSync(
"filesMoved3.csv",
project +
"," +
name +
"," +
className +
"," +
date +
"\n"
);
}
}
});
}
}
});
}
});
}
});
}
I have been stuck on this issue for some time now. I am calling an API - get the results just fine. I am saving the values to an array. The problem which I am encountering is trying to get specific values from the array. I have a for in loop running which takes time, so when the if statement is ran the loop hasn't reached that value. If I use Postman, I see that the value exists, its just the loop doesn't execute in time. Here is my code:
var msg = {};
var embed = {};
var link = {};
var msgIn = [];
var rel = [];
return SkypeService.getEvent(msg).then(function (result) {
msg.eventsNext = result._links.next.href;
if (result && result.sender && result.sender.length > 0) {
if (result.sender) {
for (var item in result.sender) {
var event = result.sender[item].events;
for (var key in event) {
embed = event[key]._embedded;
msgIn.push(embed);
}
for (var key in event) {
link = event[key].link;
rel.push(link);
}
// console.log(Object.entries(msgIn))
if(rel['rel'] == 'message') {
console.log("message is there")
if(msgIn.message) {
console.log("links exist")
if(msgIn.message.direction == "Incoming") {
console.log("direction is there")
msg.participant = msgIn.message._links.participant.href;
msg.contMsg = msgIn.message._links.messaging.href;
msg.msgIn = msgIn.message._links.plainMessage.href;
break;
}
}
}
if(rel['rel'] == "messagingInvitation"){
console.log("invite there")
if(msgIn.messagingInvitation && msgIn.messagingInvitation.state !== "Failed") {
console.log("invite link")
if(msgIn.messagingInvitation.direction == "incoming") {
console.log("direction invite")
msg.msgInviteState = msgIn.messagingInvitation._links.state;
msg.acceptInvite = msgIn.messagingInvitation._links['accept'].href;
msg.msgIn = msgIn.messagingInvitation._links.message.href;
break;
}
}
}
if(rel['rel'] == 'messaging') {
console.log('messaging there')
if(msgIn.messaging) {
if(msgIn.messaging.state == "Disconnected") {
console.log("msgn Disconnected")
msg.addMsg = msgIn.messaging._links.addMessaging.href;
break;
}
}
}
}
}
}
console.log(msg)
})
Also, I've attached a screenshot of my local host printing the msgIn which shows that the keys exists.
When I test the code running sails lift, I can see that msgIn prints a couple of times each one increasing in length. This is what makes me think the for loop has not completed by the time the if statement runs.
Please help - I really need for this to be resolved. I need to capture the links so that I can use those in the next step.
Thanks.
I have resolved my issue by making changes to the code. Here is the new version:
return
SkypeService.getEvent(msg).then(function
(result) {
msg.eventsNext = result._links.next.href;
if (result.sender) {
for (var item in result.sender) {
var event = result.sender[item].events;
for (var key in event) {
embed = event[key]._embedded;
link = event[key].link;
};
if(link['rel'] == 'message') {
console.log("message is there")
if(embed.message) {
console.log("links exist")
if(embed.message.direction == "Incoming") {
console.log("direction is there")
msg.participant = embed.message._links.participant.href;
msg.contMsg = embed.message._links.messaging.href;
msg.msgIn = embed.message._links.plainMessage.href;
break;
}
}
};
if(link['rel'] == "messagingInvitation"){
console.log("invite there")
if(embed.messagingInvitation) {
console.log("invite link")
if(embed.messagingInvitation.direction == "incoming") {
console.log("direction invite")
msg.msgInviteState = embed.messagingInvitation._links.state;
msg.acceptInvite = embed.messagingInvitation._links['accept'].href;
msg.msgIn = embed.messagingInvitation._links.message.href;
break;
}
}
};
if(link['rel'] == 'messaging') {
console.log('messaging there')
if(embed.messaging) {
if(embed.messaging.state == "Disconnected") {
console.log("msgn Disconnected")
msg.addMsg = embed.messaging._links.addMessaging.href;
break;
}
}
};
console.log(msg)
};
};
});
I have removed the result validation and simplified the for (var key in event) to handle both operations in one. Also, I have removed the arrays which I was pushing the values into as I was not using that. That may have been the time consuming factor which was preventing me from getting the direction validated.
i having Api Call which execute in For Loop some of the value which returns 10 sec itself some may take nearly 60 sec i have to maintain proper Timeout and clear session (i.e if results comes at 15 sec means it should goes to next input values and run the code) but currenly its waiting for 45 sec each single record how to optimize it
here my sample code :
if (selectedrows.length >= 1) {
for (var i = 0; i < selectedrows.length; i++) {
var myVar = setTimeout (function (k) {
var ob = { results: "Appending ..." };
child.update(selectedrows[k][4], selectedrows[k][4], ob);
var fullName = selectedrows[k][1] + ' ' + selectedrows[k][2];
math.ResultCall.async(fullName,function (err, res) {
if (err) throw err;
var returnedValue = JSON.parse(res);
console.log(returnedValue);
if(returnedValue.Result == null || returnedValue.Result.FOUND_Result == null)
{
console.log("None found")
}
else{
var obj = { results: “res” };
child.update(selectedrows[k][4], selectedrows[k][4], obj);
}
}
});
}, i * 45000,i);
}
}
Rephrasing your question, you need to return the data when your api gets resolved.
For this please go through https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve
JavaScript, by default it work asynchronously because of its event loop.
You have promises and resolve to get notified when your api returns a data
Hope I helped :)
There are several approaches to implement the solution
1. Async-Await: in-case the records-processing order is important
for( let i=0; i<selectedrows.length; i++)
{
let ob = { results: "Appending ..." };
child.update(selectedrows[i][4], selectedrows[i][4], ob);
let fullName = selectedrows[i][1] + ' ' + selectedrows[i][2];
await new Promise((resolve,reject)=>
{
math.ResultCall.async(fullName,(err, res) => {
if (err) reject(err);
let returnedValue = JSON.parse(res);
console.log(returnedValue);
if(returnedValue.Result == null || returnedValue.Result.FOUND_Result == null) {
console.log("None found")
} else {
let obj = { results: “res” };
child.update(selectedrows[i][4], selectedrows[i][4], obj);
}
resolve();
});
}
**don't forget this means the wrapping function should be async as well (which returns a promise that can be resolved if necessary)
2.Promise.All: if the order is not important
let promArray = [];
for( let i=0; i<selectedrows.length; i++)
{
let ob = { results: "Appending ..." };
child.update(selectedrows[i][4], selectedrows[i][4], ob);
let fullName = selectedrows[i][1] + ' ' + selectedrows[i][2];
promArray.push( new Promise((resolve,reject)=>
{
math.ResultCall.async(fullName,(err, res) => {
if (err) reject(err);
let returnedValue = JSON.parse(res);
console.log(returnedValue);
if(returnedValue.Result == null || returnedValue.Result.FOUND_Result == null) {
console.log("None found")
} else {
let obj = { results: “res” };
child.update(selectedrows[i][4], selectedrows[i][4], obj);
}
resolve();
});
);
}
Promise.all(promArray);
** this will also return a Promise that can be resolved if necessary.