How to wait for a function, which contains promises - javascript

If we have this function
const getData = () => {
foo()
.then(result => {
return result;
})
.catch(error => {
return error;
});
};
Although getData is not a promise itself, but it contains a promise, which is asyncrnous.
So what is the best way to wait for getData to return something. Async / Await doesn't work cause they work with promises.
Thanks.

Currently, getData() doesn't return anything. You need to make it return a Promise, so you can await it or chain .then() to it.
const getData = () => {
return foo() // <-- here
.then(result => {
return result;
})
.catch(error => {
throw error;
});
};
// Now you can do :
getData().then(...)
// or :
const data = await getData();
In this case, you can also omit the curly braces and the explicit return, and make it implicit :
const getData = () => foo()
.then(result => {
return result;
})
.catch(error => {
throw error;
});
Hey but what's that :
.then(result => {
return result;
})
This does nothing. It takes a value and simply returns it without doing anything. You can remove it.
You can now rewrite getData() this way :
const getData = async () => {
try {
return await foo()
} catch (error) {
throw error;
}
}
For that matter, this :
.catch(error => { throw error; });
or this :
catch (error) { throw error; }
are also pretty useless, they just "relay" (bubble up) the error that has to be caught in the calling function.
Now it's obvious getData does pretty much only one thing, it's returning foo(), which is a Promise. It's only a wrapper around a Promise... so it's actually pretty useless.
Bottom line, detData() is useless altogether. foo is a Promise; writing a function that returns a Promise so you can use it like a Promise is just... a Promise with an extra step. Just use foo directly.
let result;
try {
result = await foo();
} catch (error) {
console.log(error);
}
console.log(result);

This will not work because getData is not returning a value. You can add a return statement before foo call and wait for the return value.
const getData = () => {
return foo();
};
getData().then(data => {
console.log(data);
}).catch(err => {
console.log(err);
});

To wait for an operation you must return a Promise or use a callback. The code snippet below runs and should illustrate how this works. I implemented a sample foo function that is actually asynchronous (wait for 1 second before returning the data '12345'). I used async/await to illustrate how that can work, but you can equally return the result of foo and use then instead.
const foo = () => {
return new Promise(resolve => {
setTimeout(() => resolve('12345'), 1000);
});
}
const getData = async () => {
const data = await foo();
console.log(`Data is ${data}`);
return data;
};
getData()
.then(() => console.log('complete'))
.catch(err => console.log(`oops: ${err}`));
console.log('this prints first since async operation is still pending');

Related

How can I return something from the inside of this function (Javascript)?

I have this piece of code which is inside a function that is called by another second function. Now I have no clue, how to return the result to the second function.
(async () => {
try {
const response = await axios.get(knockoutCityURL);
console.log(response.data["1301210"].data.price_overview);
} catch (error) {
console.log(error.response.body);
}
})();
I would be very happy if you could help me.
Remove the IIFE, and just return the Axios promise from a simple function, then make your second function async, and await the data.
(Here's a JSFiddle as async/await doesn't work in a snippet)
function fn1() {
// return axios.get(knockoutCityURL);
return new Promise((res, rej) => {
setTimeout(() => res('Hallo'), 2000);
});
}
async function fn2() {
const data = await fn1();
console.log(data);
}
fn2();

How to execute an await method after another await using javascript and react?

i have code like below
const somePromises = values.map(({variable, value}) =>
this.post('/api/values/', {
variable,
value,
item: itemId,
})
);
await Promise.all(somePromises);
if (somecondition) {
params.var = var;
await this.patch('/api/items/${itemId}/', params);
}
the above code works but i want to execute if clause only if there is values has some value or if somePromises is resolved.
so was trying something like below,
const somePromises = values.map(({variable, value}) =>
this.post('/api/values/', {
variable,
value,
item: itemId,
})
);
await Promise.all(somePromises).then (() => {
if (somecondition) {
params.var = var;
await this.patch('/api/items/${itemId}/', params); //but throws err here
}
});
but throws error await cant be used here and async should be used. how can i fix this issue.
could someone help me with this. thanks.
Assuming this.patch returns a Promise, you can return it if it passes the conditions, or return a resolved Promise:
Promise.all(somePromises).then(() => {
if (somecondition) {
return this.patch('/api/items/${itemId}/', params);
} else {
return Promise.resolve(null);
}
}).then(response => {
if (response) {
// do something with response, the returned value from this.patch
}
});
You are using await inside your callback function body. So, that callback function also should by async if you want to await inside it.
await Promise.all(somePromises).then(async () => {
if (somecondition) {
params.var = var;
await this.patch('/api/items/${itemId}/', params);
}
})

Javascript async function return then-catch promise?

Introduction
I am new in the world of javascript promises and I need to understand how they work correctly...
Until know I have been doing this in my code:
const handleRefresh = () => {
setIsRefreshing(true);
fetchUserData()
.then(async () => { <--------- Using then because I return a promise in fetchUserData
await fetchUserPosts(); <------- Using await here
setIsRefreshing(false);
}).catch(err => { <--------- This will catch the error I have thrown in the function fetchUserPosts or inside the then body
// TODO - Show error
setIsRefreshing(false);
console.log(err)
);
};
const fetchUserData = async () => { <------ async function
const { firebase } = props;
const userId = firebase.getCurrentUser().uid;
const documentRef = firebase.getDatabase().collection("users").doc(userId);
// Fetch all the user information
return documentRef <--------- Returning the promise here
.get()
.then((doc) => {
if (doc.exists) {
// Get all user data
const data = doc.data();
console.log(data);
setUserData(data);
}
})
.catch((err) => {
throw err; <----------- Throwing error
});
};
I don't know if I am doing anti patterns... But basically I need to know if this is a good way and if I am doing this correctly.
Questions
Do I have to declare the fetchUserData function as async to return a promise?
Can I use the async await in the then/catch body?
Can I do this?
const handleRefresh = async () => {
setIsRefreshing(true);
await fetchUserData()
.then(async () => { <--------- Using then because I return a promise in fetchUserData
await fetchUserPosts(); <------- Using await here
}).catch(err => { <--------- This will catch the error I have thrown in the function fetchUserPosts or inside the then body
// TODO - Show error
console.log(err)
);
setIsRefreshing(false);
};
I would really appreciate if someone guides me. Thanks.
the words async and await are only syntactic sugar for then and catch.
This:
fetchUserData()
.then(data => return data )
.catch(error => return error)
is equivalent to:
async function getUserData() {
const userData = await fetchUserData()
return userData
}
Here you are returning anything (success or error). If you want to treat the error here, just put a try/catch clause.
async function getUserData() {
try {
return await fetchUserData()
} catch (e) {
return e.message
}
}
Note that you can only use the await clause within an async function.
1.
Function can return Promise without being declared as async as long as you don't await inside it,
2.
You should not use async-await inside then, simply return a Promise and it'll be resolved in the following then,
3.
When using async-await syntax, Promises are awaited in a declarative way as demonstrated below:
const handleRefresh = async () => {
try
{
const a = await getA()
// pass the result to another Promise
const b = await getB(a)
const c = await getC(b)
} catch (error)
{
handleError(error)
}
};

Why is Mocha returning undefined when testing function that uses a promise?

I am having an issue with Mocha returning an incorrect result when testing a function that uses a promise. Not sure why it is returning "undefined" - the function being called (testFunction()) shouldn't be returning until the promise is completed.
Test:
it('test1', function() {
let testResult = testFunction();
assert.equal(testResult,'success');
});
Promise:
getPromise() {
return new Promise((resolve, reject) => {
resolve('success');
}
}
testFunction()
testFunction = () => {
getPromise().then(result => { return result}
).catch(error =>{ return error });
}
Result:
AssertionError [ERR_ASSERTION]: undefined == 'success'
testFunction does not have a return statement in it, and so it is returning undefined. The returns in the callbacks only determine what the callbacks return, not what testFunction returns.
Since you're dealing with promises, you will have to return a promise. You can't return a string, because that string doesn't exist yet. So, testFunction might look like this:
testFunction = () => {
return getPromise()
.then(result => { return result })
.catch(error => { return error });
}
But this .then is not doing anything, so unless there's some extra code you didn't mention, it can be removed:
testFunction = () => {
return getPromise()
.catch(error => { return error; });
}
Your test will need to be written to expect a promise to be returned. This is easiest if you use an async function, as in:
it('test1', async function () {
let testResult = await testFunction();
asset.equal(testResult, 'success');
});
Alternatively, you can use a done callback to tell the test when your async work is finished.
it('test1', function (done) {
let promise = testFunction();
promise.then(testResult => {
assert.equal(testResult, 'success');
done();
});
});

What's the promise chaining equivalent of awaiting multiple async functions?

I'm studying the usage of promsies and async/await.
I've wrote the following code, which does the following:
It gets some database's data (using Knex.js),
Handles that data,
Assigns the handled data into a specified property.
These 3 steps are done multiple times (In the following code, it's done twice), and are always awaited:
async function run() {
return await getData();
}
async function getData() {
let handledData = {};
handledData.res1 = await knex.select('column1').from('table1').where('column1', '1')
.then(data => handleData(data))
.catch(handleError);
handledData.res2 = await knex.select('column1').from('table1').where('column1', '2')
.then(data => handleData(data, handledData))
.catch(handleError);
return handledData;
}
async function handleData(data) {
let res = [];
data.forEach(item => {
res.push(item.column1);
});
return res;
}
function handleError (error) {
console.log(error);
}
Now, I'm trying to write the promise-chaining equivalent of getData, and this is what I came up with:
async function getData() {
let handledData = {};
let promise = new Promise(function(resolve, error){ resolve(); });
promise
.then(function () {
return knex.select('column1').from('table1').where('column1', '1')
.then(data => handleData(data))
.catch(handleError);
})
.then(function(handled){
handledData.res1 = handled;
return knex.select('column1').from('table1').where('column1', '2')
.then(data => handleData(data))
.catch(handleError);
})
.then(function(handled){
handledData.res2 = handled;
return handledData;
})
.catch(handleError);
return promise;
}
But this doesn't quite work. What happens is that after the first then returns, the await inside run ends its awaiting, which causes run to return - and only then the second then is executed.
How can I make the promise-chaining version work as the multiple-await version does?
(and please, feel free to point out any misunderstaings I made of promises/async-await)
If possible, I'd recommend using Promise.all instead, it'll make your script run faster in addition to making the logic clearer:
const getData = Promise.all([
knex.select('column1').from('table1').where('column1', '1')
// Simply pass the function name as a parameter to the `.then`:
.then(handleData)
.catch(handleError),
knex.select('column1').from('table1').where('column1', '2')
.then(handleData)
.catch(handleError)
])
.then(([res1, res1]) => ({ res1, res2 }));
knex.select().then() returns a promise, so you don't need to wrap it in another promise you just need to set up the chain of then()s and return the whole thing. The result will be that getData returns the promise from the last then. You can return the value you want from that then() which will make it available to the caller. For example:
function run() {
getData()
.then(handledData => console.log(handledData) /* do something with data */)
}
function getData() {
let handledData = {};
// need to return this promise to callers can access it
return knex.select('column1').from('table1').where('column1', '1')
.then(data => handledData.res1 = handleData(data))
.then(() => knex.select('column1').from('table1').where('column1', '2'))
.then(data => {
handledData.res2 = handleData(data)
return handledData
})
.catch(handleError);
}
You could also set this up to pass the handledData object thought the chain, but you don't need to in this case.
The function handleData() is synchronous, so you don't need to make it an async function.

Categories