i recieve some data from x API, but i am stuck between a rock, if i want to use 'states' variable into another function, for example i want to map json object like this :
of course, it shows me error, 'state is not define';
any short way to solve this problem?
//recieve data
window.onload = async () => {
const response = await fetch("x");
const states = await response.json();
console.log(states);
};
states.map(function(bra){
// something
}
You do not need to access local variables, if you use vanilla JS you can do something like this:
const request = async () => {
const response = await fetch("x");
const data = await response.json();
renderYourData(data);
}
const renderYourData = (data) => {
//apend your data in DOM
}
window.addEventListener('load', function() {
request();
});
But if you use SPA framework it's no a better approach;
Related
I have been working with the fetch API and got the data logged to the console successfully from the then() but I am looking for a way to put this data in a global variable that I will use later. I was able to do this with reactjs because of its state management but in vanilla javascript, it is hard to do due to the promise returned
Things I have tried
const res = await fetch('./data.json')
.then(res => res.json())
.then(data => data) // when I log from here I get the data but can't assign it to a global variable even tried using `var`
using async/await still no hope.
const fun = async () => {
const response = await fetch("https://jsonplaceholder.typicode.com/todos/1");
return response.json()
}
Inside an asynchronous function getData which fetches the remote data, you can get the parsed JSON body as a JavaScript object and assign it to a variable dataGlobal defined in the global context.
Of course, you have to wait for getData to execute before dataGlobal is declared. Therefor, I'm using an asynchronous IIFE.
let dataGlobal;
const getData = async () => {
const response = await fetch("https://jsonplaceholder.typicode.com/todos/1");
const data = await response.json();
dataGlobal = data;
return data;
};
(async () => {
await getData();
console.log(dataGlobal);
})();
While I understand that you'd like a global variable for your data, I would advise against polluting the global namespace (see also: [1], [2], [3] and [4]).
You could instead encapsulate everything in an Immediately Invoked Function Expression (IIFE), and have your fetch method inside of it with all of the code related to that area of your program.
Then, by rearranging #alexanderdavide's answer, we get the following code:
(async () => {
let data_local;
const getData = async () => {
const response = await fetch("https://jsonplaceholder.typicode.com/todos/1");
const data = await response.json();
dataGlobal = data;
return data;
};
await getData();
console.log(data_local);
// your code goes here...
})();
You could also use the following alternative as well:
(async () => {
const getData = async () => {
const response = await fetch("https://jsonplaceholder.typicode.com/todos/1");
const data = await response.json();
dataGlobal = data;
return data;
};
let data_local = await getData();
console.log(data_local);
// your code goes here...
})();
That way your data_local variable would be available to everything beneath it but not outside of the IIFE itself, protecting the global namespace while allowing multiple methods access to the same variable without using callbacks with a data argument.
NOTE: please be careful if/when you change the data variable, you might end up changing it multiple times and inadvertently causing an error because of missing / improperly formatted data.
Good luck.
I'm new to async operations and js. Here is my question.
I have a Person class. I want to init Person instance using data that I get from an API call.
class Person {
constructor(data) {
this.data = data;
}
}
I am making an API call using Axios. I get a response and want to use it in my class.
const res = axios.get('https://findperson.com/api/david');
const david = new Person(res);
I understand that res is a promise at this stage, and that I need to consume it.
How should I do it?
How can I take the response and use it properly?
axios.get() return a promise of an object which contains the returned data, status, headers, etc...
async function getPerson() {
try {
const res = await axios.get('https://findperson.com/api/david');
const david = new Person(res.data);
// do something with david
} catch (error) {
console.log(error)
}
}
or
function getPerson() {
axios
.get('https://findperson.com/api/david')
.then(res => {
const david = new Person(res.data)
// do something with david
})
.catch(console.log)
}
Inside another async function, or at the top level of a module or at the REPL (in node 16.6+ or some earlier versions with the --experimental-repl-await feature enabled), you can just use await.
const res = await axios.get('https://findperson.com/api/david');
That will wait for the promise to be resolved and unwrap it to store the contained value in res.
If you want to get the value out of the world of async and into synchro-land, you have to do something with it via a callback function:
axios.get('https://findperson.com/api/david').then(
res => {
// do stuff with res here
});
... but don't be fooled; without an await, any code that comes after that axios.get call will run immediately without waiting for the callback. So you can't do something like copy res to a global var in the callback and then expect it to be set in subsequent code; it has to be callbacks all the way down.
You can do this:
axios.get('https://findperson.com/api/david').then(res => {
const david = new Person(res);
});
Or in async function: (See async await for javascript)
const res = await axios.get('https://findperson.com/api/david');
const david = new Person(res);
I simply want to load a JSON and store to a variable/array so that I could load the JSON api once and use the array to work with. Is there a way to fetch and store a JSON to a variable that I can access outside the fetch() or $.getJSON async functions?
I've come up with the code below, but I'm afraid it will load the JSON api everytime I call the function 'test'. Am I right?
function test(callback) {
$.getJSON('myURL', function (data) {
callback(data);
});
}
test(function (data) {
console.log(data);
});
If the data at myURL doesn't change, then one option is to have test cache the resolve value (or Promise), so that only one network request is made (and, for easy asynchronous use, use fetch, which returns a native Promise):
const test = (() => {
let prom = null;
return () => {
if (!prom) {
prom = fetch('myUrl').then(res => res.json());
}
return prom;
};
})();
test()
.then((data) => {
console.log(data);
});
You just need to declare the variable outside of the getJSON function:
var saved_data = null;
function test(callback) {
$.getJSON('', function (data) {
saved_data = data;
for(var i=0; i<saved_data.length; i++){
$('.list').append('<li data-id="'+i+'">'+saved_data[i].title+'</li>')
}
}, 1000);
}
test();
$(document).on('click', '.list li', function(){
console.log(saved_data[$(this).data('id')])
});
The first thing about asynchronous functions is that you have to wait for them to finish (and you don't know how long that can take), before you continue with your flow. In Javascript there are two ways to address that - using the Promise API or using a callback function. In your example you have a callback that's passed to getJSON, once that callback is fired, you will have the response data inside the saved_data variable.
If you populate the links in the callback, then you can be sure that whenever a link is clicked your saved_data variable will be available, holding the data from the API response.
JSFiddle
You can always assign the data to a variable outside of the callback. I usually do this inside of then().
const apiCall = new Promise(resolve => {
setTimeout(() => {
resolve('Data here')
}, 1000)
})
let result
apiCall.then(data => {
result = data
console.log(result)
})
And using async/await:
const apiCall = new Promise(resolve => {
setTimeout(() => {
resolve('Data here')
}, 1000)
})
const asyncFunction = async () => {
const result = await apiCall
console.log(result)
}
asyncFunction()
I want to get a value from an API and save that value for later, but I'm having troubles.
I get the result I want when I use console.log(), but when I do exactly the same thing with "return()" I get this result:
Promise{< resolved >:"The value I want"}
I'll show you my code:
const getDataAA = async () => {
const response = await fetch("https://s3.amazonaws.com/dolartoday/data.json")
const data = await response.json()
console.log("async/await based")
console.log(data.USD.transferencia)
}
When I call getDataAA() I get what I want in the console, but I want to store that value in order to use it, so I changed "console.log(data.USD.transferencia)" for "return(data.USD.transferencia)".
Then I do something like this in order to save the value:
let dolarPrice = getDataAA()
Why when I use "console.log" I get the value but when I use "return" I get also the promise?
const getDataAA = async () => {
const response = await fetch("https://s3.amazonaws.com/dolartoday/data.json")
return response.json()
}
let response = await getDataAA();
console.log(response);
-- EDITED
so this one another example how use it.
the async method (getDataAA) have to return something.
everytime you need to call an async method you have to use await (
if you wait until it's completed)
everytime you use await the method must be async.
<!DOCTYPE html>
<html>
<script type="text/javascript">
var f = async () => {
const getDataAA = async () => {
const response = await fetch("https://s3.amazonaws.com/dolartoday/data.json")
return response.json()
}
let response = await getDataAA();
console.log(response);
}
f();
</script>
</html>
I discovered I way to solve this! I defined a variable outside the function and then the function stored the value I wanted inside that variable. This is my code:
const getDataAA = async () => {
const response = await fetch("https://s3.amazonaws.com/dolartoday/data.json")
const data = await response.json()
console.log("async/await based")
dolarPrice = (data.USD.transferencia)
}
let dolarPrice
getDataAA()
That way I stored the value inside the "dolarPrice" variable. Thanks all the people who answered my question, I found the solution thanks to all of you.
I'm fetching my user data and the map function is called several times for each user. I want to wait until all data was pushed to the array and then manipulate the data. I tried using Promise.all() but it didn't work.
How can I wait for this map function to finish before continuing?
Needless to say that the array user_list_temp is empty when printed inside the Promise.all().
const phone_list_promise_1 = await arrWithKeys.map(async (users,i) => {
return firebase.database().ref(`/users/${users}`)
.on('value', snapshot => {
user_list_temp.push(snapshot.val());
console.log(snapshot.val());
})
}
);
Promise.all(phone_list_promise_1).then( () => console.log(user_list_temp) )
I changed the code to this but I still get a wrong output
Promise.all(arrWithKeys.map(async (users,i) => {
const eventRef = db.ref(`users/${users}`);
await eventRef.on('value', snapshot => {
const value = snapshot.val();
console.log(value);
phone_user_list[0][users].name = value.name;
phone_user_list[0][users].photo = value.photo;
})
console.log(phone_user_list[0]);
user_list_temp.push(phone_user_list[0]);
}
));
console.log(user_list_temp); //empty array
}
It is possible to use async/await with firebase
This is how I usually make a Promise.all
const db = firebase.database();
let user_list_temp = await Promise.all(arrWithKeys.map(async (users,i) => {
const eventRef = db.ref(`users/${users}`);
const snapshot = await eventref.once('value');
const value = snapshot.value();
return value;
})
);
This article gives a fairly good explanation of using Promise.all with async/await https://www.taniarascia.com/promise-all-with-async-await/
Here is how I would refactor your new code snippet so that you are not mixing promises and async/await
let user_list_temp = await Promise.all(arrWithKeys.map(async (users,i) => {
const eventRef = db.ref(`users/${users}`);
const snapshot= await eventRef.once('value');
const value = snapshot.val();
console.log(value);
phone_user_list[0][users].name = value.name; // should this be hardcoded as 0?
phone_user_list[0][users].photo = value.photo; // should this be hardcoded as 0?
console.log(phone_user_list[0]);
return phone_user_list[0]; // should this be hardcoded as 0?
})
);
console.log(user_list_temp);
Here is a simple example that uses fetch, instead of firebase:
async componentDidMount () {
let urls = [
'https://jsonplaceholder.typicode.com/todos/1',
'https://jsonplaceholder.typicode.com/todos/2',
'https://jsonplaceholder.typicode.com/todos/3',
'https://jsonplaceholder.typicode.com/todos/4'
];
let results = await Promise.all(urls.map(async url => {
const response = await fetch(url);
const json = await response.json();
return json;
}));
alert(JSON.stringify(results))
}
If I understand your question correctly, you might consider revising your code to use a regular for..of loop, with a nested promise per user that resolves when the snapshot/value for that user is available as shown:
const user_list_temp = [];
/*
Use regular for..of loop to iterate values
*/
for(const user of arrWithKeys) {
/*
Use await on a new promise object for this user that
resolves with snapshot value when value recieved for
user
*/
const user_list_item = await (new Promise((resolve) => {
firebase.database()
.ref(`/users/${users}`)
.on('value', snapshot => {
/*
When value recieved, resolve the promise for
this user with val()
*/
resolve(snapshot.val());
});
}));
/*
Add value for this user to the resulting user_list_item
*/
user_list_temp.push(user_list_item);
}
console.log(user_list_temp);
This code assumes that the enclosing function is defined as an asynchronous method with the async keyword, seeing that the await keyword is used in the for..of loop. Hope that helps!