I have an es6 class, with an init()
method responsible for fetching data, transforming it, then update the class's property this.data
with newly transformed data.
So far so good.
The class itself has another getPostById()
method, to just do what it sounds like. Here is the code for the class:
class Posts {
constructor(url) {
this.ready = false
this.data = {}
this.url = url
}
async init() {
try {
let res = await fetch( this.url )
if (res.ok) {
let data = await res.json()
// Do bunch of transformation stuff here
this.data = data
this.ready = true
return data
}
}
catch (e) {
console.log(e)
}
}
getPostById(id){
return this.data.find( p => p.id === id )
}
}
Straightforward, except I have an async/await
mechanism in the init()
method.
Now, this code will work correctly:
let allPosts = new Posts('https://jsonplaceholder.typicode.com/posts')
allPosts.init()
.then( d => console.log(allPosts.getPostById(4)) )
// resulting Object correctly logged in console
but it only gets printed into the console:
How could I use allPosts.getPostById(4)
as a return
of a function ?
Like:
let myFunc = async () => {
const postId = 4
await allPosts.init() // I need to wait for this to finish before returning
// This is logging correct value
console.log( 'logging: ' + JSON.stringify(allPosts.getPostById( postId ), null, 4) )
// How can I return the RESULT of allPosts.getPostById( postId ) ???
return allPosts.getPostById( postId )
}
myFunc()
returns a Promise
but not the final value. I have read several related posts on the subject but they all give example of logging, never returning.
Here is a fiddle that includes two ways of handling init()
: using Promise
and using async/await
. No matter what I try, I can't manage to USE the FINAL VALUE of getPostById(id)
.
The question of this post is: how can I create a function that will RETURN the VALUE of getPostById(id)
?
EDIT:
A lot of good answers trying to explain what Promises are in regards to the main execution loop. After a lot of videos and other good reads, here is what I understand now:
my function init()
correctly returns. However, within the main event loop: it returns a Promise, then it is my job to catch the result of this Promise from within a kinda parallel loop (not a new real thread). In order to catch the result from the parallel loop there are two ways:
use .then( value => doSomethingWithMy(value) )
use let value = await myAsyncFn()
. Now here is the foolish hiccup:
await can only be used within an
async
function :p
thus itself returning a Promise, usable with await
which should be embed in an async
function, which will be usable with await
etc...
This means we cannot really WAIT for a Promise: instead we should catch parallel loop indefinitely: using .then()
or async/await
.
Thanks for the help !
To our code, it does not make any difference whether console. log is async or not, it does not provide any kind of callback or so; and the values you pass are always referenced and computed at the time you call the function.
To return values from async functions using async-await from function with JavaScript, we return the resolve value of the promise. const getData = async () => { return await axios.
Async functions always return a promise. If the return value of an async function is not explicitly a promise, it will be implicitly wrapped in a promise.
Async functions The word “async” before a function means one simple thing: a function always returns a promise. Other values are wrapped in a resolved promise automatically. So, async ensures that the function returns a promise, and wraps non-promises in it.
NOTE: Wherever you use await
it has to be inside an async
function.
Check out the UPDATED FIDDLE
You need to use await myFunc()
to get the value you expect from getPostById
because an async function always returns a promise.
This sometimes is very frustrating as the whole chain needs to be converted into async
functions but that's the price you pay for converting it to a synchronous code, I guess. I am not sure if that can be avoided but am interested in hearing from people who have more experience on this.
Try out the below code in your console by copying over the functions and then accessing final
and await final
.
NOTE:
An async function CAN contain an await expression. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
There is no rule that is must have await in order to even declare an async function. The example below uses an async function without await just to show that an async function always returns a promise.
const sample = async () => {
return 100;
}
// sample() WILL RETURN A PROMISE AND NOT 100
// await sample() WILL RETURN 100
const init = async (num) => {
return new Promise((resolve, reject) => {
resolve(num);
});
}
const myFunc = async (num) => {
const k = await init(num);
return k;
}
// const final = myFunc();
// final; This returns a promise
// await final; This returns the number you provided to myFunc
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With