This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 1 year ago.
I hope this is not a duplicate. So far I could find a few tutorials and questions about this - but usually everyone just wants to log the results of their code to console, which is not helping me.
I want to fetch some data from an API to plot it on a website.
The fetching seems to work fine, because I can log the results inside the fetch.then() to the console. But (obviously) they do not make their way outside of the fetch.
The only solution I was able to find is to wrap this whole thing in another function or to write a function that works with the data fetched inside of the .then().
I couldn't make the first idea work, because I cannot return anything for the same reason as above (the data does not make it's way outside of the .then()).
The second one is problematic, because I simply want to plot the results from a few .json entries to a Plotly plot. And I have honestly no idea how to place this inside of a function.
// Arrays for results
var sugars = [];
var times = [];
// fetch the BG data from the API and write results into arrays
fetch(url)
.then((resp) => {return resp.json()})
.then( (result) => {
// read glucose values from json
// logging the results/sugars/times to console from here works!
for (let i = 0; i < n_entries; i++) {sugars[i] = result[i]["sgv"]}
for (let i = 0; i < n_entries; i++) {times[i] = -i * timestep}
});
var x1;
var y1;
/*
// Dummy data to test plotly, these WORK for some reason.
x1 = [0, -5, -10, -15, -20];
y1 = [123, 119, 113, 107, 102];
*/
// These values, however, don't work:
/*
x1 = times;
y1 = sugars;
// this yields 'undefined' errors:
console.log(times)
*/
Maybe you can try to separate your fetch and return the data to a function where you use the data to do what you want. You can try something like this - I think it is the same as what other people commented.
//make the fetch and return response data as json
async function getData() {
let url = 'your url';
try {
let resp = await fetch(url);
return await resp.json();
} catch (error) {
console.log(error);
}
}
//do whatever you want with the data response
async function myFunc() {
let data = await getData();
//do some stuff with your data here
}
//call the function
myFunc();
Take at look at this link if you get stuck.
Related
I am writing this as a lambda function which should Display a random string out of the declared array, but upon the time of execution, it displays "NULL".
Please can anyone suggest me the correct code or syntax and tell me whats wrong with this code.
exports.handler = async (event) => {
let messages = ["AWS","Pranav","Hello World"];
let response = messages[Math.floor(Math.random()*100)];
return response;
};
Nothing to do with Lambda, error is in the way you take a random array element.
Change it to this:
exports.handler = async (event) => {
let messages = ["AWS","Pranav","Hello World"];
let response = messages[Math.floor(Math.random()*messages.length)];
return response;
};
Instead of multiplying Math.random() by 100, which gives you a random number between 0 and 100, you should multiply it by messages.length.
More examples on generating a random number in JS here: https://stackoverflow.com/a/24152886/2727317
I'm making a Trivia Game and I'm using The Open Trivia Database to generate 10 random questions.
These 10 questions are separate strings and I want to place them into an array so that I can display them one by one (after the user guesses whether it's True or False.)
Here is the console log of the questions:
Now here is what I'm trying: I have initialized an empty array and then, in the for loop, I'm pushing each question into the array but its not working.
Essentially, what I'm trying to achieve is that when the user clicks a true or false button, the next item in the response will be displayed. I thought an array would work but maybe I'm looking at it in the wrong way.
Any help is appreciated and if I missed something, please let me know. Thank you in advance!
Code:
const api_url =
"https://opentdb.com/api.php?amount=10&difficulty=easy&type=boolean";
const triviaQ = document.getElementById("triviaQuestion");
const question_array = []; // this is the empty array
async function getAPI(url) {
const response = await fetch(url);
var data = await response.json();
justQuestions(data);
}
function justQuestions(data) {
/// loop to display all 10 questions
for (let i = 0; i <= 9; i++) {
display_all_questions = data.results[i].question;
current_question = triviaQ.innerHTML = display_all_questions; /// the console log image
let all_questions = question_array.push({ display_all_questions }); //this is where I attempt to add the questions into an array
}
}
First, you are creating a variable 'all_questions' on each iteration and never use it (you don't need it). Second, 'display_all_questions' name is misleading, as it is just the current question.
And finally, your data.results is already the array that you need, so you can just use it like this:
let questions_array = [];
async function getAPI(url) {
const response = await fetch(url);
var data = await response.json();
questions_array = data.results;
console.log(questions_array);
}
Don't forget to handle possible network request errors
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 1 year ago.
I have a txt file containing a list of all Italian words (link) that I want to read and then convert to an array of words, but I'm a bit stuck on the reading part. The file was originally downloaded from the web, so it might or might not have some encoding issues.
To read the file, I am using Fetch, with the same code suggested in the top answer of this post. After reading it, if I use alert(storedText) the text is correctly displayed; however, if I try var s = storedText.toString() and then alert(s) I get "undefined" in the alert box.
I guess there is some problem when reading the file, but I'm rather new to JavaScript and I can't figure out what exactly the problem is. Do you guys have any idea?
Edit: this is my full code
var storedText;
fetch('http://doodlemarty.unaux.com/wp-content/uploads/2021/08/parole.txt')
.then(function(response) {
response.setContentType("text/html;charset=UTF-8");
response.text().then(function(text) {
storedText = text;
done();
});
});
var s = storedText.toString();
var fullList = storedText.split('\n');
function test () {
//first try:
alert(storedText);
//second try:
alert(s);
//trying split:
alert(fullList[2]);
};
I have the test function execute when a button is clicked.
This seems like a async issue with promises. You are trying to access storedText before its value is updated in the fetch operation.
Try this:
var storedText;
var s;
var fullList;
async function callFetch() {
let response = await fetch('http://doodlemarty.unaux.com/wp-content/uploads/2021/08/parole.txt')
response.setContentType("text/html;charset=UTF-8");
let text = await response.text();
storedText = text;
}
function setVariables() {
s = storedText.toString();
fullList = storedText.split('\n');
}
async function test() {
await callFetch();
setVariables();
//first try:
alert(storedText);
//second try:
alert(s);
//trying split:
alert(fullList[2]);
};
I am trying to scrape data from a bricklet in the UI(i.e. HTML dataTable) and using a testCafe client function to do this but I haven't been successful. I have a few questions about my code and would like someone to point me in the right direction.
I first put my client function in the test file(test.js) which houses all my other test cases and called the function from one of my tests. Just like this example here: - https://devexpress.github.io/testcafe/documentation/test-api/obtaining-data-from-the-client/examples-of-using-client-functions.html check section "complex DOM queries" but testCafe gets stuck, the browser closes but the execution is stuck
Here is my client function. It is in my file that houses all my tests - test.js
fixture`Getting Started`
.page`${config.baseUrl}`;
const getTableRowValues = ClientFunction(() => {
console.log("inside client function");
const elements = document.querySelector('#bricklet_summary_studtable > tbody').querySelectorAll('tr td');
const array = [];
console.log(elements.length);
for (let i = 0; i <= elements.length; i++) {
console.log("inside for");
const customerName = elements[i].textContent;
array.push(customerName);
}
return array;
});
Here is my test case:
test('My 4th test - Check the bricklet data matches the expected data', async t => {
await t.navigateTo('https://myurl.com/app/home/students');
await page_studTest.click_studentlink();
await t
.expect(await page_studTest.exists_ListPageHeader()).ok('do something async', { allowUnawaitedPromise: true })//check the compare button does not exists
await t .navigateTo('https://myurl.com/app/home/students/application/stud/id/details/test.html')
await t
.expect(await page_studTest.getText_studHeader(t)).eql('student123',
"the header text does not match");
let arr = await getTableRowValues();
await console.log(arr);
});
I thought this will get the values from the UI in an array and I will compare it to another array of test values that I will hard code later.
At first, I tried client functions in my page class(page object model: https://devexpress.github.io/testcafe/documentation/recipes/use-page-model.html) and I put the client function in the constructor and called it from a async function in same page class and called the async function from my test.js. All my tests are structured this way but this only prints the following in the console
Valuesfunction __$$clientFunction$$() {
const testRun = builder._getTestRun();
const callsite = (0, _getCallsite.getCallsiteForMethod)(builder.callsiteNames.execution);
const args = [];
// OPTIMIZATION: don't leak `arguments` object.
for (let i = 0; i < arguments.length; i++) args.push(arguments[i]);
return builder._executeCommand(args, testRun, callsite);
}
which is not useful to debug the problem.
There are no examples on testCafe site as to how/where to put the client function when you use the page-object model. Could someone, please share some insight? I am interested in knowing the best way to structure my tests.
I didn't find any problems in your code which can make TestCafe hang. I didn't find any syntax errors or incorrect calls to TestCafe methods either. I only wish that you take note that the await keyword should not be called before console.log. Though this should not lead to any issues.
Probably the use of a custom promise with the { allowUnawaitedPromise: true } option can lead to problems, however it's difficult to determine it without the full project.
I recommend you prepare a simple project with a sample test file to demonstrate the issue and create a separate bug report in the TestCafe repository using the following form
So, finally I tried to return a promise from my client function and then it worked.
const getTableRowValues = ClientFunction(() => {
const array = [];
return new Promise(resolve => {
var elements = document.querySelectorAll('#bricklet_summary_studtable > tbody > tr > *');
elements.forEach(function (element, i) {
let text = element.textContent;
array[i] = text.trim();
});
resolve(array);
});
});
I resolve a single dimensional array as the assertion wasn't working with a 2D array in the test when I compare the result of the client function to a 2D expected value.However this serves the purpose for now.
I'm using this Gumroad-API npm package in order to fetch data from an external service (Gumroad). Unfortunately, it seems to use a .then() construct which can get a little unwieldy as you will find out below:
This is my meteor method:
Meteor.methods({
fetchGumroadData: () => {
const Gumroad = Meteor.npmRequire('gumroad-api');
let gumroad = new Gumroad({ token: Meteor.settings.gumroadAccessKey });
let before = "2099-12-04";
let after = "2014-12-04";
let page = 1;
let sales = [];
// Recursively defined to continue fetching the next page if it exists
let doThisAfterResponse = (response) => {
sales.push(response.sales);
if (response.next_page_url) {
page = page + 1;
gumroad.listSales(after, before, page).then(doThisAfterResponse);
} else {
let finalArray = R.unnest(sales);
console.log('result array length: ' + finalArray.length);
Meteor.call('insertSales', finalArray);
console.log('FINISHED');
}
}
gumroad.listSales(after, before, page).then(doThisAfterResponse); // run
}
});
Since the NPM package exposes the Gumorad API using something like this:
gumroad.listSales(after, before, page).then(callback)
I decided to do it recursively in order to grab all pages of data.
Let me try to re-cap what is happening here:
The journey starts on the last line of the code shown above.
The initial page is fetched, and doThisAfterResponse() is run for the first time.
We first dump the returned data into our sales array, and then we check if the response has given us a link to the next page (as an indication as to whether or not we're on the final page).
If so, we increment our page count and we make the API call again with the same function to handle the response again.
If not, this means we're at our final page. Now it's time to format the data using R.unnest and finally insert the finalArray of data into our database.
But a funny thing happens here. The entire execution halts at the Meteor.call() and I don't even get an error output to the server logs.
I even tried switching out the Meteor.call() for a simple: Sales.insert({text: 'testing'}) but the exact same behaviour is observed.
What I really need to do is to fetch the information and then store it into the database on the server. How can I make that happen?
EDIT: Please also see this other (much more simplified) SO question I made:
Calling a Meteor Method inside a Promise Callback [Halting w/o Error]
I ended up ditching the NPM package and writing my own API call. I could never figure out how to make my call inside the .then(). Here's the code:
fetchGumroadData: () => {
let sales = [];
const fetchData = (page = 1) => {
let options = {
data: {
access_token: Meteor.settings.gumroadAccessKey,
before: '2099-12-04',
after: '2014-12-04',
page: page,
}
};
HTTP.call('GET', 'https://api.gumroad.com/v2/sales', options, (err,res) => {
if (err) { // API call failed
console.log(err);
throw err;
} else { // API call successful
sales.push(...res.data.sales);
res.data.next_page_url ? fetchData(page + 1) : Meteor.call('addSalesFromAPI', sales);
}
});
};
fetchData(); // run the function to fetch data recursively
}