This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 2 years ago.
I am very new to JavaScript, trying to understand the concepts of asynchronous function. So, basically I wrote a webScraper for RateMyProfessor using nightmare. This is the function:
var Nightmare = require("nightmare"),
nightmare = Nightmare();
const baseURL =
"https://www.ratemyprofessors.com/search.jsp?queryBy=schoolId&schoolName=University+of+California+Santa+Barbara&schoolID=1077&queryoption=TEACHER";
const getRatingProfessor = (professorName) => {
let rating;
let nameSplitter = professorName.split(" ");
if (nameSplitter.length > 2) {
professorName = nameSplitter[0] + " " + nameSplitter[1];
}
nightmare
.goto(baseURL)
.click("#ccpa-footer > .close-this")
.type("#professor-name", professorName)
.wait(1000)
.evaluate(() => {
var resultList = document.querySelectorAll("a .rating");
//if no result is found
if (typeof resultList === "undefined" || resultList.length == 0) {
return "Not Found";
}
//Found the professor with exact name
if (resultList.length == 1) {
return document.querySelector("a > .rating").innerHTML;
}
//conficting similar professor names (rare case)
if (resultList.length >= 2) {
return "Cannot Determine";
}
})
.end()
.catch((err) => {
console.log(err);
})
.then((text) => {
rating = text;
console.log(professorName, text);
});
return rating;
};
console.log(getRatingProfessor("XXXXX"));
If I run this program, it gives the following output:
undefined
SomeProfName 4.8
It seems like the function returned the rating to console.log without waiting for the promise. Why isn't function not waiting for the nightmare promise to get resolved. More importantly, why isn't the value of rating getting updated; or it has been updated but console.log doesn't want to wait for the function?
Sorry, these questions may look absurd, but I would really appreciated the answers :0
Your function explicitly does not return anything hence will return undefined by default. What you are getting is correct but within the then()...
If you wanted to return an async result you'd need to declare your function as async and then await the result.
const getRatingProfessor = async (professorName) => {
let rating;
let nameSplitter = professorName.split(" ");
if (nameSplitter.length > 2) {
professorName = nameSplitter[0] + " " + nameSplitter[1];
}
await text = nightmare...
return text;
};
(async () => {
console.log(await getRatingProfessor("XXXXX"));
}
)()
Related
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed last year.
let found = false;
axios
.get(link)
.then((response) => {
response.data.map((element) => {
if (element.id_ticket.toString() === nbTicket) found = true;
});
console.log(found);
});
so im trying to get data from the api and see if the value of 'nbTicket' is in the returned data and that is done using the 'found' variable so if i log the 'found' variable value outside the .then method it stays false even if the value exists and when i do it iside the .then methods it gives the correct value
let found = false;
axios
.get(link)
.then((response) => {
response.data.map((element) => {
if (element.id_ticket.toString() === nbTicket) found = true;
});
});
console.log(found);
Your supposed to use async/await strategy, because console.log happens after Axios request:
async function getNbTicket(){
let found = false;
const { data } = await axios.get(link);
data.data.map((element) => {
if (element.id_ticket.toString() === nbTicket) found = true;
});
return found;
}
your console.log(found); is executing is executing before you fetch data from api
you can call it inside then or use async await if you want to call console.log(found); after you get data from api
This is normal behavior, because of the async and sync.
you have two options
first one is to wrap your code inside a async function
const checkIfTicketIsFound = async () => {
let found = false;
const { data } = await axios.get(link);
data.map((element) => {
if (element.id_ticket.toString() === nbTicket) found = true;
})
console.log(found)
return found
}
Or
you need to print inside the then chain
let found = false;
axios
.get(link)
.then((response) => {
response.data.map((element) => {
if (element.id_ticket.toString() === nbTicket) found = true;
});
console.log(found);
});
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 2 years ago.
I tried to fetch some information through a API and it worked. The next step was to define "ourserver" with the right server data. So I made a foreach and I console-logged just server and got the right one, but if I try to define ourserver = server; the last console log is showing me that ourserver is still undefined.
let ip = "myserverip";
let ourserver;
const fetchPromise = fetch('http://myapi.com/list/servers')
fetchPromise.then(response => {
return response.json();
}).then(list => {
list.forEach(function (server) {
if (server.host === ip) {
ourserver = server;
// console.log(server); this was defined
}
});
});
console.log("daten: " + ourserver); // this is after all still undefined
The reason you are seeing this issue is because your code to define ourserver actually occurs after your console.log("daten: " + ourserver);, you can prove this to yourself by logging the date, too:
ourserver = server;
console.log(server, new Date());
...
console.log("daten: " + ourserver,new Date());
You will see the daten console.log occurs before your log of server.
When you call fetch, it will perform the fetching in the background, and once it has completed, it will call the function provided to then. This is how asynchronous programming works in JavaScript.
Your code that requires ourserver to be present should happen in your then.
Here's your code modified to show how I would go about this:
const ip = "myserverip";
fetch('http://myapi.com/list/servers').then(response => {
return response.json();
}).then(list => {
return list.find(server => server.host === ip);
}).then(ourserver => {
console.log("daten: " + ourserver);
});
If you absolutely must access the value of ourserver outside of the fetch, this can be achieved one of two ways. One way is to define a callback, and the other way is to wait for the value to be set. Here are both ways:
callback
const ip = "myserverip";
let ourserver = null;
const callback = () => {
console.log(ourserver);
}
fetch('http://myapi.com/list/servers').then(response => {
return response.json();
}).then(list => {
ourserver = list.find(server => server.host === ip);
callback();
});
wait
const ip = "myserverip";
let ourserver = null;
fetch('http://myapi.com/list/servers').then(response => {
return response.json();
}).then(list => {
ourserver = list.find(server => server.host === ip);
});
const check = () => {
if(ourserver == null){
return setTimeout(check,100);
}
console.log(ourserver);
};
check();
I do not recommend using the wait and check solution.
read more about Async JS and promise, the reason for this that
fetch promise will run
it's an async operation so the interpreter will not wait until it finish so he will continue execution for the rest of the file.
it will print the console.log
and if the async operation finished the call back will be put in something called event queue, and if the call stack is empty, the event loop will execute your callback function which be the function inside .then in your case.
let ip = "myserverip";
let ourserver;
async function fetchPromise(){
try{
const response = await fetch('http://myapi.com/list/servers');
const list = await response.json();
list.forEach((server) => {
if (server.host === ip) {
ourserver = server;
}
});
console.log("daten: " + ourserver);
}catch(e){
console.log(e);
}
}
You can make use of async/await to handle the fetch better and for a cleaner code. This way you gonna wait until you get the response from the fetch api and then you will have the value of ourserver available.
This question already has answers here:
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
Closed 2 years ago.
With the following function I am trying to calculate the total price of a checkout. But if I console.log() the variable before it is returned, I get 0. If I console.log() the variable in the findOne() function, I get the correct value.
As database I use MongoDB and "Item" is a model.
function calculateOrderAmount(items) {
var totalPayment=0;
items.forEach((item) => {
Item.findOne( { _id: item } )
.then(item => {
if(item) {
// Item exists
totalPayment = item.price;
console.log(totalPayment);
}
});
});
console.log(totalPayment);
return totalPayment;
}
I'm desperate about it and I don't really know what to look for on the internet. Many thanks for answers in advance.
Item.findOne is an async operation, so in your code you execute:
var totalPayment = 0
items.forEach((item) => {...
console.log(totalPayment)
return totalPayment
other sync code who called calculateOrderAmount
then the callback of Item.findOne is run
You must use a callback sytle or an async function like this:
async function calculateOrderAmount (items) {
// beware: if you have a huge items list, doing so could lead to high memory usage
const itemsPromises = items.map((item) => {
return Item.findOne({ _id: item })
.then(item => {
if(item) {
// Item exists
return item.price;
}
return 0
});
})
const prices = await Promise.all(itemsPromises)
const totalPayment = prices.reduce((a, b) => a + b, 0)
console.log(totalPayment)
return totalPayment
}
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 3 years ago.
Below is my JS Method
function test(key, language) {
var uri = '/Resources/ValidationMessages.json';
fetch(uri).then(response => {
return response.json();
}).then(data => {
console.log('Inside Function - ' + data[key]);
return data[key];
}).catch(err => {
console.log(' Error ');
});
}
And after calling this method as
var v = test('spnrequiredRegisterEmail');
console.log('Outside Function - ' + v);
Inside the function it print value but Outside Function statement is always undefined.
The solution that I am trying to achieve is that I have to set some text in n number of span as inner text, which will come through this function call after passing the respective key, but every span displays undefined as inner text
It won't wait for a method to finish , so how can I solve this issue?
Try using async / await
async function test(key, language) {
try {
var uri = '/Resources/ValidationMessages.json';
var resp = await fetch(uri);
var data = resp.json();
console.log('Inside Function - ' + data[key]);
return data[key];
catch(err) {
console.log(err);
}
}
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 4 years ago.
I'm developing a google chrome extension and I have to loop trough the nodes (folders) to check how many items I have within each folder. I'm suppling an item ID to the function getBookmarksCount(ID). I'm having an issue to get a result from the main function the console.log() returns correct value at the point of logging.
Here is my code:
const getBookmarksCount = (bmkNode) => {
let nodes = []
let result = 0
new Promise ((resolve, reject) => {
chrome.bookmarks.getChildren(bmkNode, (bmkChildren) => {
_.each(bmkChildren, (item) => {
// Check if the item is a bookmark link
if (!(item.url === undefined || item.url === null)) {
nodes.push(item.title)
}
})
resolve(_.size(nodes))
})
}).then((size) => {
console.log(size) //The correct number of items is listed here eg. 6
result = size
})
return result
}
//I'm suppling a parent folder ID the function should return number of children
getBookmarksCount(123) // eg. 6 -> at the moment returns 0
Here is my updated working version without Promise. setTimeout() is a dirty hack but works. Any suggestions how I can improve this function?
const getBookmarksCount = (bmkNode) => {
let nodes = []
const getChildrenCount = (bmkNode) => {
chrome.bookmarks.getChildren(bmkNode, (bmkChildren) => {
_.each(bmkChildren, (item) => {
// if is bookmark otherwise loop trough subfolder
(!(item.url === undefined || item.url === null)) ? nodes.push(item.title): getChildrenCount(item.id)
})
})
setTimeout(() => {
$(`#counter_${bmkNode}`).html(_.size(nodes))
}, 50)
}
getChildrenCount(bmkNode)
}
// HTML Template
<label class="label label-primary" id="counter_${item.id}">0</label>
As pointed out by Bravo in the comments, you are not really waiting for your code to execute. You are ever so close, though!
const getBookmarksCount = (bmkNode) => {
return new Promise ((resolve) => {
let nodes = []
chrome.bookmarks.getChildren(bmkNode, (bmkChildren) => {
_.each(bmkChildren, (item) => {
// Check if the item is a bookmark link
if (!(item.url === undefined || item.url === null)) {
nodes.push(item.title)
}
})
resolve(_.size(nodes))
})
})
}
getBookmarksCount(123).then(size => {
console.log(size)
})
Note the return new Promise on the second line, which is a key difference from your provided snippet. By doing this, you wait to "return" here until you actually finish the async work and call resolve. Then, to get the value returned, you would do the same .then syntax you used but at the call of getBookmarksCount.
Hopefully that helps and, of course, also works!