How can i use promise.all with forEach in asynchronous function - reactjs

i have a asynchronous function inside that am using forEach and promise.all. my question is how can i make the function stops until one of the value in forEach is rendered completely and then go for the next one.
sentingMailtoOneRestauarnt this is a large function and now am getting only partial values from this because next value in forEach is invoked before the completion of first one.
exports.handler = async () => {
return fetchAllConnectedAcccounts(null).then((response) => {
var promises_array = []
response.forEach((data) => {
if (data) {
var promise = sentingMailtoOneRestauarnt(data, yesterday).then((resp)=>{
promises_array.push(promise);
})
}
})
return Promise.all(promises_array).then((result) => {
return result;
})
}).catch((err) => {
console.log(err)
});
}

From the code, looks like you already are using async here. Skip ove promises -
const responses = await fetchAllConnectedAcccounts(null);
const results = [];
for (const response of responses){
if (response){
results.push(await sentingMailtoOneRestauarnt(response, yesterday));
}
}
// do whatever with results...

Currently your array is full of resolved promises (you push to it only after promise is resolved).
exports.handler = async () => {
return fetchAllConnectedAcccounts(null).then((response) => {
var promises_array = []
response.forEach((data) => {
if (data) {
var promise = sentingMailtoOneRestauarnt(data, yesterday);
promises_array.push(promise); // push to array before promise is resolved
}
})
return Promise.all(promises_array); // wait for resolving here
/*.then((result) => {
return result;
})*/ // unnecessary
}).catch((err) => {
console.log(err)
});

Related

I have problem with read promise from async function in my react app with

When I console.log($a) in readData function a get object, but when I use this function in another component I get promise. I need to get object not promise.
async function readData(collectionName) {
try {
const querySnapshot = await getDocs(collection(db, collectionName));
let $a = [];
querySnapshot.forEach((doc) => {
$a.push({ id: doc.id, ...doc.data() });
});
console.log($a); // get object
return $a;
} catch (err) {
console.error(err);
}
}
const addProd = () => {
const products = readData("products");
console.log(products); // get promise, but I need object
};
Add await to the
const products = await readData("products");
This is because you are not waiting for the promise to be resolved and simply console logging straight away

Why Promise.all is not getting values?

I am using React and inside useEffect I am pulling data but I am getting an emtpy array after all the promises are resolved and cannot figure out why.
Here is the code:
const data = mainnet.FairLaunch.pools.map((pool) => {
const loadingStakingData = async () => {
const stakedValue = await getStakeValue(pool);
const poolDaily = await getPoolDaily(pool);
console.log( { stakedValue, poolDaily }) // all good here and printing what it has to print
return { stakedValue, poolDaily };
};
return loadingStakingData();
});
Promise.all(data).then((values) => {
console.log('value', values) // not logging anything here
setStakingData(values);
}); // always an empty array
Any idea why this is happening?
You might be returning a pending promise in the map function. Maybe try this code instead to return the value
const data = mainnet.FairLaunch.pools.map(async (pool) => {
const stakedValue = await getStakeValue(pool);
const poolDaily = await getPoolDaily(pool);
console.log( { stakedValue, poolDaily }) // all good here and printing what it has to print
return { stakedValue, poolDaily };
});
Promise.all(data)
.then((values) => {
console.log('value', values)
setStakingData(values);
})
.catch(console.error) // Remember to catch errors!!!

using axios with promise API

I am using a promise based hook in a React app to fetch async data from an API.
I am also using a Axios, a promise based http client to call the API.
Is it an anti-pattern to use a promise based client inside another promise? The below code does not seem to work.
const getData = () => {
return new Promise((resolve, reject) => {
const url = "/getData";
axios.get(url)
.then(function(response) {
resolve(response);
})
.catch(function(error) {
reject(error);
});
});
const useAsync = (asyncFunction) => {
const [value, setValue] = useState(null);
const execute = useCallback(() => {
setPending(true);
setValue(null);
setError(null);
return asyncFunction()
.then(response => setValue(response))
.catch(error => setError(error))
.finally(() => setPending(false));
}, [asyncFunction]);
useEffect(() => {
execute();
}, [execute]);
return { execute, pending, value, error };
};
};
const RidesList = () => {
const {
pending,
value,
error,
} = useAsync(getData);
Oh man. I think you have a fundamental misunderstanding about how Promises work.
First, axios already returns a Promise by default. So your whole first function of getData can be reduced to:
const getData = () => {
const url = "/getData"
return axios.get(url)
}
But the meat of your code seems to indicate you want a querable Promise - so you can check the status of it for whatever reason. Here's an example of how you would do it, adapted from this snippet:
function statusPromiseMaker(promise) {
if (promise.isResolved) return promise
let status = {
pending: true,
rejected: false,
fulfilled: false
}
let result = promise.then(
resolvedValue => {
status.fulfilled = true
return resolvedValue
},
rejectedError => {
status.rejected = true
throw rejectedError
}
)
.finally(() => {
status.pending = false
})
result.status = () => status
return result
}
In this way, you can then do something like let thing = statusPromiseMaker(getData()) and if you look up thing.status.pending you'll get true or false etc...
I didn't actually run what's above, I may have forgotten a bracket or two, but hopefully this helps.
I have to admit - I haven't seen anything like this ever used in the wild. I am interested in knowing what you're actually trying to accomplish by this.
Axios itself returns a promise but if you want to make a custom class having your custom logic after each API call then you can use interceptors I was having the same requirement and this is how I am returning promises after applying my custom logic on each API call.
Interceptors will get executed separately after and before each request you made so we can simply use them if we want to modify our request or response.
here is my working solution have a look at it.
callApi = (method, endpoint, params) => {
this.apiHandler.interceptors.request.use((config) => {
config.method = method
config.url = config.baseURL + endpoint
config.params = params
return config
})
return new Promise((resolve, reject) => {
this.apiHandler.interceptors.response.use((config) => {
if (config.status == 200) {
resolve(config.data)
} else {
reject(config.status)
}
// return config
}, error => reject(error))
this.apiHandler()
})
}
Below is the code to call this function
helper.callApi("get", "wo/getAllWorkOrders").then(d => {
console.log(d)
})

React native, can't acess elements in array

I have a little problem accessing the elements in an array in react native.
I have the problem with the following code:
GetStockPrice = () => {
var stockPrice = StockLogic.getStockPrice();
console.log(stockPrice)
for (let index = 0; index < stockPrice.length; index++) {
console.log(stockPrice[index]);
}
};
The StockLogic.getStockPrice() looks like this:
getStockPrice() {
var stockPricesJSON = [];
this.stocknames.forEach(stock => {
var url =
"https://api.iextrading.com/1.0/stock/" +
stock +
"/batch?types=quote,news,chart&range=1m&last=10";
fetch(url)
.then(resp => resp.json())
.then(data =>
stockPricesJSON.push(
[data.quote.symbol, data.quote.open, data.quote.close, Number(((data.quote.open - data.quote.close)).toFixed(1))]
)
);
});
return stockPricesJSON;
}
If I run the GetStockPrice function, I only get the console.log() of the stockPrice that is passed from the other class. But the logs from the loop don't show up.
I guess that the problem is in the StockLogic, but I can't figure it out.
I hope you can help me once again.
Hope you have a nice day.
Iywern
Because both fetch and forEach are asyncrhonous, stockPricesJSON is being returned as an empty array.
For something like this you'll want to use Promise.all:
function getStockPrice() {
var stockPricesJSON = [];
var promises = this.stocknames.map(stock => {
var url =
"https://api.iextrading.com/1.0/stock/" +
stock +
"/batch?types=quote,news,chart&range=1m&last=10";
return fetch(url);
});
Promise.all(promises).then(function(stocks) {
stocks.forEach(function(stock) {
//...your code
})
})
}
Note that you may need to call Promise.all two times which might look something like this:
Promise.all(promises).then(function(stocks) {
var jsonpArr = stocks.map(function(stock) {
return stock.jsonp();
});
Promise.all(jsonpArr).then(function(stocks) {
stocks.forEach(function(stock) {
//...your code here
});
});
});
And finally instead of returning that value I would suggest you store it with redux or your component state using setState. If this function does not belong to a component then I would suggesting wrapping the entire thing in a promise
new Promise(function(resolve, reject) {
//...your code
})
and calling resolve() on the result
To further improve this I would highly suggest using async/await along with a more modern syntax
const getStockPrice = () => {
return new Promise( async (resolve, reject) => {
try {
let promises = this.stocknames.map(stock => {
var url =
"https://api.iextrading.com/1.0/stock/" +
stock +
"/batch?types=quote,news,chart&range=1m&last=10";
return fetch(url)
})
let result = await Promise.all(promises)
let stocks = await Promise.all(result.map(r => r.jsonp()))
stocks.forEach(stock => {
//...your code
resolve(result)
})
} catch(e) {
reject(e)
}
})
}
And as always, documentation is your friend!
Promise.all()
async / await
I believe this is problem is related to the asynchronous way promises calls are executed. I had a similar problem and I had to run a function like getStockPrice within the response section of your code and assign the result to a state variable.

need to know when all async operation completed

I have the following code:
callAPI() {
return this.myModel.map(action(retValue => {
return this.myApi.doWork(retValue.Input).then(action(model => {
this.model.Input = Object.assign({}, model);
this.saveState();
})).catch(error => {
throw(error);
});
}));
if my client code I am doing something like this:
myStore.callAPI().then(() => {
console.log("completed");
this.setState({ loading: false });
});
I am getting an error
.then() is not a function
I want to get a callback when all async operations are completed.
Please use Promise.all to await multiple promises and return the result which is another Promise which you can call .then on.
In order to always return a promise after an imperative block of code you can return Promise.resolve() that will make the code chainable.
callAPI() {
return Promise.all(
this.myModel.map(action(retValue => (
this.myApi.doWork(retValue.Input).then(action(model => {
this.model.Input = Object.assign({}, model);
this.saveState();
return Promise.resolve();
}))
)));
);
}
Please see an example:
const sleep = timeout => new Promise(resolve =>
setTimeout(() => resolve(timeout), timeout)
);
const tap = timeout => {
console.log(`Task completed after ${timeout}ms`);
return timeout;
}
const tasks = [
sleep(1000),
sleep(2000),
sleep(500),
sleep(30),
sleep(2500),
sleep(450)
].map(task => task.then(tap));
Promise.all(tasks).then(x => {
console.log(x);
});

Resources