export function RecommendList(data) {
return (dispatch, getState) => {
let db = loadFB().firestore();
let query = db.collection('users').where("recommend", ">", "0").orderBy("recommend", "asc")
let user_list = [];
let uid_arr=[];
let result = [];
query.get().then(async docs => {
docs.forEach(doc => {
const recommender = doc.data();
const recommend_id = recommender.recommend;
const recommend_person = recommender.displayName;
user_list.push({id : recommend_id, recommend_person : recommend_person });
})
uid_arr = getRecommendList(user_list);
console.log("getRecommendList",uid_arr);
for(let i = 0; i < uid_arr.length; i++) {
const user_doc = await db.collection('users').doc(uid_arr[i].id).get();
console.log(user_doc.data());
let user_info = user_doc.data()
user_info.betball_dupli_count = uid_arr[i].count;
user_info.recommend_person = uid_arr[i].person;
console.log('displayname' , user_info.displayName , 'betball count',user_info.betball_dupli_count,'person',user_info.recommend_person);
result.push(user_info);
}
console.log('result!', result);
dispatch({
type: types.SET_USER_LIST,
data: result,
page: 1
})
})
}
}
I work on importing data from the Fire Store and sending it to the dispatch.
By the way, I want to make a code that increases the efficiency of this work by asynchronous mode in javascript. I'd like to know how to wait and process a form asynchronously.
In short, how to turn "for" of this code into async mode!
With minimal changes to your existing code:
let userQueries = [];
for (let i = 0; i < uid_arr.length; i++) {
userQueries.push(
db.collection('users').doc(uid_arr[i].id).get()
.then(user_doc => {
console.log(user_doc.data());
let user_info = user_doc.data()
user_info.betball_dupli_count = uid_arr[i].count;
user_info.recommend_person = uid_arr[i].person;
console.log('displayname', user_info.displayName, 'betball count', user_info.betball_dupli_count, 'person', user_info.recommend_person);
result.push(user_info);
})
)
}
await Promise.all(userQueries);
The outer for loop will just initiate the queries and the then part of each one will run when the specific query is complete. Outside of the for loop, the Promise.all call will wait for all of the queries to complete before continuing.
Related
When I run this code it give me a random order of Pokémons. I don't know where is the problem.
Thank you so much.
for (var i = 1; i <= 20; i++) {
apiPokemon("https://pokeapi.co/api/v2/pokemon/"+i);
async function apiPokemon(urlPokemon) {
const response = await fetch(urlPokemon);
const dataPokemon = await response.json();
var id = dataPokemon.id;
var name = dataPokemon.name;
console.log(id, name);
}
}
First thing's first: "Why are they coming back in random order?" - Because you are not awaiting each response. Instead you are firing off all 20 async calls which can come back in any order, so that's why they are logging in a random order.
In order to fix this, there are a few changes I'd recommend:
Extract your apiPokemon function out of your loop so it doesn't get recreated for each loop iteration
Return the entire data object from your apiPokemon function
Add all of the apiPokemon requests to an array and await them with Promise.all()
Log the output of the Promise.all() and you'll see that they will now always be in correct order
async function apiPokemon(urlPokemon) {
const response = await fetch(urlPokemon);
const dataPokemon = await response.json();
return dataPokemon;
}
async function getPokemon(startIndex, stopIndex) {
let requests = [];
for (let i = startIndex; i <= stopIndex; i++) {
requests.push(apiPokemon("https://pokeapi.co/api/v2/pokemon/"+i));
}
let pokemonList = await Promise.all(requests);
for (let pokemon of pokemonList) {
console.log(pokemon.id, pokemon.name);
}
}
getPokemon(1, 20)
I am fairly new to Javascript and I understand that it executes asynchronously. I tried using the callback method to fetch the secret values and then execute next block of code. But it is not waiting.
This is the function that fetches the keyvault secret values
function getsecret_values(client,secret_name,callback) {
let val = []
for (let i =0;i<secret_name.length;i++){
client.getSecret(secret_name[i]).then((latestSecret) => {
val[i] = latestSecret.value;
})
}
callback(val)
}
I am calling getsecret_values function from main block
let vaultName = result.database;
const url = `https://${vaultName}.vault.azure.net`;
const credential = new ClientSecretCredential(result.host, result.user, result.password);
const client = new SecretClient(url, credential);
let secret_values = []
getsecret_values(client, secrets, function(result) {
secret_values = result
console.log(secret_values)
});
console.log(secret_values)
\\next code block
Both the console.log returns empty array.
I want my code to wait till the secret values are fetched and put into secret_values array and then proceed to next block of code. How do I achieve this?
the easiest way is to use Async Await pattern, which uses promises in the background. Trying not to change your code much:
async function getsecret_values(client,secret_name) {
let val = []
for (let i =0;i<secret_name.length;i++){
const latestSecret = await client.getSecret(secret_name[i])
val[i] = latestSecret.value;
}
return val
}
in your main block:
getsecret_values(client, secrets).then(function(result) {
secret_values = result
console.log(secret_values)
});
console.log(secret_values) // will still be an empty array as the then function has not been executed yet....
my approach would be:
async function getsecret_values(client,secret_name) {
let val = []
for (let i =0;i<secret_name.length;i++){
const latestSecret = await client.getSecret(secret_name[i])
val[i] = latestSecret.value;
}
return val
}
// main:
async function main() {
let vaultName = result.database;
const url = `https://${vaultName}.vault.azure.net`;
const credential = new ClientSecretCredential(result.host, result.user, result.password);
const client = new SecretClient(url, credential);
const secret_values = await getsecret_values(client, secrets)
console.log(secret_values)
}
main()
im doing orders onsnapshot from firebase but im confused how to deal with it, I get an [] when I log it out but when I logout the type of orders it says object,
I'm trying to add the id of each order and place it inside the array orders along with the existing data but its not working , if I
console.log(orders[0]) I get undefined and if I treat it as an object orders['0'] i also get undefined.
here is the code:
im using vuejs mounted
async mounted() {
let id = [];
let orders = [];
await db.collection("orders").onSnapshot(doc => {
doc.docs.forEach(x => {
id.push(x.id);
orders.push(x.data());
});
});
for (order in orders) {
let i = 0;
order.id = id[i];
i++
}
console.log(orders);
}}
the result of this code is the same orders array without any change at all.
Data is loaded from Firestore asynchronously. While that is happening, your main code continues to execute, so that the user can continue to use the app.
What this means in practice is that in your code the console.log(orders) is executed before any of the orders.push(x.data()) is ever run.
The solution is pretty simple: any code that needs the data from the database, needs to be inside the callback that is called with the data:
async mounted() {
let id = [];
let orders = [];
db.collection("orders").onSnapshot(doc => {
doc.docs.forEach(x => {
id.push(x.id);
orders.push(x.data());
});
for (order in orders) {
let i = 0;
order.id = id[i];
i++
}
console.log(orders);
});
}
}
Alternatively, you can use async and await to handle the asynchronicity, but in that case you should use get instead of onSnapshot and not use a callback:
async mounted() {
let id = [];
let orders = [];
const snapshot = await db.collection("orders").get();
snapshot.docs.forEach(x => {
id.push(x.id);
orders.push(x.data());
});
for (order in orders) {
let i = 0;
order.id = id[i];
i++
}
console.log(orders);
}
You should check first, returning snap is either object or array. Generally I found it return object. Hence you should do like.
mounted = async () => {
let id = [];
let orders = [];
db.collection("orders").on("value", async snapshot => {
let ordersData = snapshot.val();
if (ordersData !== null) {
Object.values(ordersData).map(item => {
orders = [...orders, item.data]; //map according to your data
});
}
console.log("orders===>", orders);
});
};
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.
I know Js is async but how to prevent my callback from returning an empty array ?
Here is my code :
function getPicturesArray(nbr,callback){
var avatarArr = [];
for(var i =0; i<nbr ; ++i){
request("https://randomuser.me/api/",{json: true},(err,response,body)=> {
avatarArr.push(body.results[0].picture.large);
});
}
callback(avatarArr);
}
getPicturesArray(12, (e)=>{
console.log(e);
});
console.log('here');
And the sout is:
[]
here
I'm mocking the calls with a public service for demonstration purposes, but the key point here is the asynchronous nature of HTTP requests.
When you invoke callback(avatarArr);, your for loop IS done but the (in this case 12) requests you sent are not, so avatarArr does not have any items yet.
Notice async before function getPicturesArray, and await before fetch
await tells the execution to wait for the fetch call to finish
You MUST check out async/await.
async function getPicturesArray(nbr,callback){
var avatarArr = [];
console.log('loading...');
for(var i =0; i<nbr ; ++i){
const response = await fetch(`https://jsonplaceholder.typicode.com/todos/${i+1}`);
const json = await response.json();
avatarArr.push(json.title);
}
console.log('done loading...');
callback(avatarArr);
}
getPicturesArray(12, (e)=>{
console.log(e);
});
console.log('see how this is executed before done loading...');
Don`t use callbacks. Use Promises or async/await.
getUserPic = async () => {
const url = 'https://randomuser.me/api/'
const response = await fetch(url)
const users = await response.json()
return users.results[0].picture.large
}
;(async () => {
const userAvatars = []
for (let i = 0; i < 12; i++) {
userAvatars.push(await getUserPic())
}
console.log(userAvatars)
})()
Also try to use this.
In this case I advice you to use Set instead of Array to exclude duplicate items.
getUserPic = async () => {
const url = 'https://randomuser.me/api/'
const response = await fetch(url)
const users = await response.json()
return users.results[0].picture.large
}
getMultipleUserPics = async limit => {
const userAvatars = new Set()
while (userAvatars.size != limit) {
userAvatars.add(await getUserPic())
}
return userAvatars
}
;(async () => {
const userPics = await getMultipleUserPics(5)
console.log(userPics)
})()
The console in the end returns empty array.
The console runs before ids.map function finishes
var ids = [];
var allLync = []
var user = await User.findOne(args.user)
ids.push(user._id)
user.following.map(x => {
ids.push(x)
})
ids.map(async x => {
var lync = await Lync.find({ "author": x })
lync.map(u => {
allLync.push[u]
})
})
console.log(allLync)
What am I doing wrong?
The .map code isn't awaited, so the console.log happens before the mapping happens.
If you want to wait for a map - you can use Promise.all with await:
var ids = [];
var allLync = []
var user = await User.findOne(args.user)
ids.push(user._id)
user.following.map(x => {
ids.push(x)
})
// note the await
await Promise.all(ids.map(async x => {
var lync = await Lync.find({ "author": x })
lync.map(u => {
allLync.push(u); // you had a typo there
})
}));
console.log(allLync)
Note though since you're using .map you can shorten the code significantly:
const user = await User.findOne(args.user)
const ids = users.following.concat(user._id);
const allLync = await Promise.all(ids.map(id => Lync.find({"author": x })));
console.log(allLync);
Promise.map() is now an option that would be a tiny bit more succinct option, if you don't mind using bluebird.
It could look something like:
const user = await User.findOne(args.user);
const ids = users.following.concat(user._id);
const allLync = await Promise.map(ids, (id => Lync.find({"author": x })));
console.log(allLync);
http://bluebirdjs.com/docs/api/promise.map.html. I have really enjoyed using it.