Async function returning promise, instead of value
I'm trying to understand how async/await works in conjunction together with promises.
Code
async function latestTime() {
const bl = await web3.eth.getBlock('latest');
console.log(bl.timestamp); // Returns a primitive
console.log(typeof bl.timestamp.then == 'function'); //Returns false - not a promise
return bl.timestamp;
}
const time = latestTime(); // Promise { <pending> }
Issue
As far as I understand, await should be blocking and in the code above it seemingly blocks returning an object bl
with the primitive timestamp
. Then, my function returns the primitive value, however the time variable is set to a pending promise instead of that primitive. What am I missing?
Async prefix is a kind of wrapper for Promises.
async function latestTime() {
const bl = await web3.eth.getBlock('latest');
console.log(bl.timestamp); // Returns a primitive
console.log(typeof bl.timestamp.then == 'function'); //Returns false - not a promise
return bl.timestamp;
}
Is the same as
function latestTime() {
return new Promise(function(resolve,success){
const bl = web3.eth.getBlock('latest');
bl.then(function(result){
console.log(result.timestamp); // Returns a primitive
console.log(typeof result.timestamp.then == 'function'); //Returns false - not a promise
resolve(result.timestamp)
})
}
An async
function always returns a promise. That's how it reports the completion of its asynchronous work. If you're using it in another async
function, you can use await
to wait for its promise to settle, but in a non-async
function (often at the top level or in an event handler), you have to use the promise directly, e.g.:
latestTime()
.then(time => {
console.log(time);
})
.catch(error => {
// Handle/report error
});
If you're doing this at the top level of a JavaScript module, some environments now support the upcoming top-level await
in modules:
const time = await latestTime();
JavaScript engines are getting support for top-level await
, and Webpack has experimental support for it, for instance.
Here's a rough translation of your async
function in explicit Promise terms:
function latestTime() {
return new Promise((resolve, reject) => {
web3.eth.getBlock('latest')
.then(bl => {
console.log(bl.timestamp);
console.log(typeof bl.timestamp.then == 'function');
resolve(bl.timestamp);
})
.catch(reject);
});
}
Some important notes on that:
- The function you pass to
new Promise
(the promise executor function) gets called synchronously bynew Promise
.- Which is why the operation starts,
web3.eth.getBlock
is called synchronously to start the work.
- Which is why the operation starts,
- Any error (etc.) thrown within the promise executor gets caught by
new Promise
and converting into a promise rejection. - Any error (etc.) thrown within a promise callback (like the one we're passing
then
) will get caught and converted into a rejection.
async
function will return Promise
anyway. Return value will be `Promise, so in your case it will be:
async function latestTime(): Promise<some primitive> {
const bl = await web3.eth.getBlock('latest');
return bl.timestamp;
}
So, further you can use it function like:
const time = await latestTime();
But for achieving general view about async/await
feature it will be better to read documentation.