JavaScript: How to wait for completion of async api call - javascript

I have an async function:
const _getSelectedComponentVariantByComponentName = async (name) => {
const response = await api.get(`/internal/api/Component/GetComponentVariantByComponentName/${name}`);
componentRow.component = response.data;
return componentRow;
};
And I'm trying to use this function inside .map() method:
let componentRows = [...getState().formulaBuilder.componentRows];
componentRows = componentRows.map(async row => {
row = await _getSelectedComponentVariantByComponentName(row.name);
return row;
});
But in this case I got a Promise with status "pending".
How to wait for completion of async api call and return a value;

You can make use of Promise.all with map and use await with it.
map will return an array of Promises, Promise.all will wait for all promises to resolve and then resolve with the values as an array for each promise.
Also make sure you execute the below code in an async function:
let componentRows = [...getState().formulaBuilder.componentRows];
componentRows = await Promise.all(componentRows.map(row => {
return _getSelectedComponentVariantByComponentName(row.name);
}));

Related

calling an async function inside for loop in JavaScript / node js

I want to call an async function inside for loop
function test(req,res){
//somelogic part here
async function create(data){
//logic part here
}
for( var value in values){
// some codeing part here
await create(data);
}
}
I am getting this error
uncaughtException: await is only valid in async function
then I can't call an async function inside For loop.
I know it is written like this but is there any possible way I can call an async function inside for loop
for await (var value in values)
Just put async in front of function test.
async function test(req, res) {…
If you want to await a promise, then the function that's using await needs to be async function.
Hi As I understood your concern I would suggest to use .map() function which is very useful in this type of case.
async function create(data) {
// Create user logic here
}
const usernames = ['test1', 'test2', 'test3'];
const createdUsers = usernames.map(async (val) => {
const user = await create();
return user;
});
await Promise.all(createdUsers);
Wrap and create new function inside another function isn't a good ideal. You can move function create to outside like the code bellow
async function create(data){
//logic part here
}
async function test(req,res){
//somelogic part here
for( var value in values){
// some codeing part here
await create(data);
}
}
Or use arrow function instead
async function test(req,res){
//somelogic part here
const create = async (data) => {
//logic part here
}
for( var value in values){
// some codeing part here
await create(data);
}
}
If calling just an asynchronous function is only going to part of your for loop mean you can simple push the promise returned by the asynchronous calls to an array and use promise static methods like 'all'
let pros= []
for(){
pro.push(create(data));
}
Promise.all(pros).then(()=> {
#implement rest or resolve another promise
})
Please refer..
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
The problem is not with your create function, but with your test function. The scope where you call the await syntax, needs to be async. Therefore, your scope here is test.
Simply update your code to the following;
/*vv --> async*/
async function test(req, res) {
console.log("test is called");
async function create(to) {
return new Promise((resolve) => {
setTimeout(() => resolve(Date.now()), to);
});
}
const values = {
a: 1e3,
b: 2e3,
c: 3e3
};
for (var value in values) {
// some codeing part here
const to = values[value];
const result = await create(to);
console.log("result:", result);
}
return 1;
}
(async() => {
const res = await test();
console.log("done");
})();
Your question is a little confusing because there doesn't appear to be any reason to async/await - create doesn't appear to return any data so the aync/await seems redundant, and you can probably remove it.
If, however, create does return a value, and you want to wait until all the values have been returned before you continue, create an array of function calls and then use Promise.all to wait until the promises returned from create have resolved.
// `create` returns a promise that resolves
// after two seconds
function create(data){
return new Promise((res, rej) => {
setTimeout(() => res(data), 2000);
});
}
async function test(req,res) {
const values = [1, 2, 3, 4];
// Create an array of promises
const arr = values.map(el => create(el));
// And use Promise.all to wait to resolve them
const output = await Promise.all(arr);
console.log(output);
}
test();
If you put the Promise in the for loop then it will get a total of every responses time in every iteration. So I'm suggesting the Promise.all for that.
async func() {
let arr = [];
for(var value in values){
arr.push(create(data));
}
let createdArr = await Promise.all(arr);
// Using createdArr, you can get all waited responses
}
In here it will get only the most responding time, not the total. All Promises run at the same time.

Async/Await returning result not promise

I'm very confused with async/await. I've been reading answers on s/o but I do not understand if async/await actually does what I want.
I'm trying to return the result of an async call in a synchronous way and maybe that's why I fail, maybe it's not made for that? I do not want to return a callback (or promise) but the result of one.
Here's what I've been trying to do
let namespace = {};
namespace.Test = class{
constructor(){
}
async get(){
let response = await this._load();
let data = await response;
console.log(data); //Logs my data but return Promise instead
return data;
}
_load(){
let promise = new Promise((resolve, reject) => {
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(function(response){
resolve(response.json());
}).catch(error => reject(error));
});
return promise;
}
}
//The goal is to figure out if I can have that
let myTest = new namespace.Test();
//Here I want data NOT a promise
let res = myTest.get();
console.log(res); //logs a Promise but I want what has been resolved instead
I thought resolving the promise inside _load and then using await inside get would do that?
I'm trying to return the result of an async call in a synchronous way
That's impossible. The only thing that is synchronously returned by an async function is a promise (all async functions return promises, by design). Async functions make the syntax for working with promises easier, but they're still asynchronous.
When you use await inside your async function, this will delay how long it takes for the returned promise to resolve. This is good: if any code is waiting on that promise, it will wait longer, and thus will hold off until your async function is completely done. But waiting for the promise is not automatic; you either need to use the promise's .then method, or need to use the await keyword inside an async function.
let resPromise = myTest.get();
resPromise.then(res => console.log(res));
async someFunction() {
const res = await myTest.get();
console.log(res);
}
as fetch() already return a promise, there is no reason to wrap it in another promise.
_load(){ return fetch('https://jsonplaceholder.typicode.com/todos/1')}
We can try this by specifying async in Self invoking function globally,
(async function() {
let namespace2 = {};
namespace2.Test = class{
constructor(){
}
async get(){
let response = await this._load();
let data = await response;
console.log(data); //Logs my data but return Promise instead
return data;
}
_load(){
let promise = new Promise((resolve, reject) => {
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(function(response){
resolve(response.json());
}).catch(error => reject(error));
});
return promise;
}
}
//The goal is to figure out if I can have that
let myTest2 = new namespace2.Test();
//Here I want data NOT a promise
let res2 = await myTest2.get();
console.log(res2);
})();
you can do this by await (see https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Operators/await)
So you just write:
//Here I want data NOT a promise
let res = await myTest.get();
And console.log(res); will now return the resolved value.

Extracting JSON from Fetch API

I realise very similar questions have been answered before, but I'm still finding it very confusing as to how this works...
From my understanding promises are used to deal with asyc requests - these promises essentially send back the state or a "promise" that at some point later a JSON body (or other object) will be delivered.
What I'm trying to understand is how I properly handle these requests so that the function doesn't return until the JSON body is ready to be parsed.
Below I'm trying to simply extract the key "result" (which returns a string "result") and parse it to another variable that can be stored and then later used somewhere else in my code. Unfortunately, my code always returns a [Object Promise], rather than the extracted JSON. I believe this is because response.json is also a promise... however, I don't understand how I get out of the "chain of promises" and return a value that I can actually do something with.
Thanks for any advice,
async function name() {
const response = await fetch('https://xxxxx.herokuapp.com/timespent', {});
const json = await response.json();
return json.result;
}
let varr = name();
console.log(varr)
Since your function is async it always return a promise. You need to use await for result.
read more about async here
async function name() {
const response = await fetch('https://mautargets.herokuapp.com/timespent', {});
const json = await response.json();
return json.result;
}
async function result(){
//await can only be called from inside of async function. So we need async function for await name()
let varr = await name();
console.log(varr) // Success
}
result()
In your example code, name function is declared async, so it returns a promise.
Inside that function body, you correctly handle async calls like fetch or the JSON transformation.
What you need now is either use await to wait for the function to "resolve", or use the "older" then/catch promises methods. Note that you cannot always use await outside an async function so you may need to wrap it.
Example :
async function name() {
const response = await fetch('https://mautargets.herokuapp.com/timespent', {});
const json = await response.json();
return json.result;
}
// using promise.then
name().then(result => console.log(result));
// wrapping await
(async function test() {
try{
console.log(await name());
}catch(error) {
// error goes here if promise got rejected
}
})()
You could have a callback in the function declaration, and use '.then(...)' and call it when the promise has been resolved:
async function name(cb) {
const response = await
fetch('https://mautargets.herokuapp.com/timespent', {});
const json = response.json();
json.then(x => cb(x))
}
name(console.log)
This is because you're using an Async function, which will return a promise.
Or if you would like the method to return, you could either call it in another Asynchronous context and utilize await again:
// Assume no callback: code just as you had it.
async function wrapper() {
console.log(await name())
}
Or you could do name().then(...) as specified before:
// Assume no callback: code just as you had it.
name().then(console.log)
Hope this helps!
I'm actually looking for the answer(same as yours), so I found this way.
I. ASK/REQUEST for data
async function fetchMyJson() {
const response = await fetch('https://1stAPI.devdeveloper1.repl.co/fiveD');
const myData = await response.json();
return myData;
}
II.GET Extract data
fetchMyJson().then(myData => {
let myData_output = myData.USD[0].rate; // fetched or Get OUTPUT data
console.log(myData_output);
document.body.innerHTML = `<div>${myData_output}</div>`; //make sure you add ${} for output
});
async function fetchMyJson() {
const response = await fetch('https://1stAPI.devdeveloper1.repl.co/fiveD');
const myData = await response.json();
return myData;
}
//GET Extract data
fetchMyJson().then(myData => {
let myData_output = myData.USD[0].rate; // fetched or Get OUTPUT data
console.log(myData_output);
document.body.innerHTML = `<div>${myData_output}</div>`; //make sure you add ${} for output
});
It is correct that you await fetch and .json since they are async.
async function name() {
const response = await fetch('http://blah.com/api', {});
const json = await response.json();
return json.result;
}
However, async and Promises inside function name make it async too. So the return value of name is a Promise that you should await it, or .then it, like:
// Old style .then
name().then(result => console.log(result))
// Modern style await
async function main() {
const result = await name()
console.log(result)
}

How to get data returned from fetch() promise?

I am having trouble wrapping my head around returning json data from a fetch() call in one function, and storing that result in a variable inside of another function. Here is where I am making the fetch() call to my API:
function checkUserHosting(hostEmail, callback) {
fetch('http://localhost:3001/activities/' + hostEmail)
.then((response) => {
response.json().then((data) => {
console.log(data);
return data;
}).catch((err) => {
console.log(err);
})
});
}
And this is how I am trying to get the returned result:
function getActivity() {
jsonData = activitiesActions.checkUserHosting(theEmail)
}
However, jsonData is always undefined here (which I am assuming is because the async fetch call has not finished yet when attempting to assign the returned value to jsonData. How do I wait long enough for the data to be returned from the fetch call so that I can properly store it inside of jsonData?
always return the promises too if you want it to work:
- checkUserHosting should return a promise
- in your case it return a promise which return the result data.
function checkUserHosting(hostEmail, callback) {
return fetch('http://localhost:3001/activities/' + hostEmail)
.then((response) => {
return response.json().then((data) => {
console.log(data);
return data;
}).catch((err) => {
console.log(err);
})
});
}
and capture it inside .then() in your main code:
function getActivity() {
let jsonData;
activitiesActions.checkUserHosting(theEmail).then((data) => {
jsonData = data;
}
}
EDIT:
Or even better, use the new syntax as #Senthil Balaji suggested:
const checkUserHosting = async (hostEmail, callback) => {
let hostEmailData = await fetch(`http://localhost:3001/activities/${hostEmail}`)
//use string literals
let hostEmailJson = await hostEmailData.json();
return hostEmailJson;
}
const getActivity = async () => {
let jsonData = await activitiesActions.checkUserHosting(theEmail);
//now you can directly use jsonData
}
You're partially right. It's because you're trying to get the result of this asynchronous call in a synchronous fashion. The only way to do this is the same way you deal with any other promise. Via a .then callback. So for your snippet:
function getActivity() {
return activitiesActions.checkUserHosting(theEmail).then((jsonData) => {
// Do things with jsonData
})
}
Any function that depends on an asynchronous operation must itself become asynchronous. So there's no escaping the use of .then for anything that requires the use of the checkUserHosting function.
You can make use of new ES6 and Es7 syntax and what others have written is also correct, but this can be more readable and clean,
you are trying to get aysnc value synchronously, here jsonData will be undefined because, you move to next line of execution before async function(checkUserHosting) is finish executing, this can be written as follows
const getActivity = async () => {
let jsonData = await activitiesActions.checkUserHosting(theEmail);
//now you can directly use jsonData
}
and you can write checkUserHosting in a different using new syntax like this
const checkUserHosting = async (hostEmail, callback) => {
let hostEmailData = await fetch(`http://localhost:3001/activities/${hostEmail}`)
//use string literals
let hostEmailJson = await hostEmailData.json();
return hostEmailJson;
}

Promise.all returns function [duplicate]

This question already has answers here:
Returning function and invoking with Promise.all
(2 answers)
Closed last month.
I would like use Async/Await with fetch API. So, i've 2 async function for return result.json().
I add my 2 Promise in Promise.all([]), but the values returned is 'function()'.
My code :
// Load external users
const externalUsers = async () => {
const result = await fetch(url);
return result.json();
};
const localUsers = async () => {
const result = await Users.allDocs({ include_docs: true });
return result.rows;
};
Promise.all([externalUsers, localUsers]).then(values => {
console.log(values); // return (2) [function, function]
});
I don't understand why. Can you help me ?
Thank you community !
Run your functions in the Promise.all. So they will return Promises which will be settled and passed to the then function.
Promise.all([externalUsers(), localUsers()]).then(values => {
console.log(values);
});
You should await your Promise.all
const values = await Promise.all([...]);
const value1 = values[0];
...
The reason you are seeing functions, is because Promise.all returns a Promise that resolves to an array. So by awaiting the Promise.all, you wait for them all to finish/resolve first.
You can also do,
const [externalUsersResult, localUsersResult] = await Promise.all([externalUsers, localUsers])

Categories