I am receiving the value of web3 within a vue.js component. I am successfully using this variable earlier in my code in the same component. However, upon trying to use it in an async function, I receive an undefined error on the said variable. Shouldn't I be able to use it as below, or am I missing something? (blockNum is being assigned a value earlier in my code.)
props: ['web3']
async function getTimestamp () {
const block = await this.web3.eth.getBlock(blockNum)
const ts = await this.web3.eth.getBlock(block).timestamp
return ts
}
console.log(getTimestamp())
Since getTimestamp is an async function, it returns a promise as opposed to the actual value. Therefore, you have to wait for the promise to resolve before console logging it.
async function getTimestamp () {
const block = await this.web3.eth.getBlock(blockNum)
const ts = await this.web3.eth.getBlock(block).timestamp
return ts
}
getTimestamp().then(ts => {
console.log(ts)
}
Related
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 2 years ago.
How can I return the value from an async function?
I tried to like this
const axios = require('axios');
async function getData() {
const data = await axios.get('https://jsonplaceholder.typicode.com/posts');
return data;
}
console.log(getData());
it returns me this,
Promise { <pending> }
You cant await something outside async scope. To get expected result you should wrap your console.log into async IIFE i.e
async function getData() {
return await axios.get('https://jsonplaceholder.typicode.com/posts');
}
(async () => {
console.log(await getData())
})()
Working sample.
More information about async/await
Since axios returns a promise the async/await can be omitted for the getData function like so:
function getData() {
return axios.get('https://jsonplaceholder.typicode.com/posts');
}
and then do same as we did before
(async () => {
console.log(await getData())
})()
your function getData will return a Promise.
So you can either:
await the function as well to get the result. However, to be able to use await, you need to be in an async function, so you need to 'wrap' this:
async function callAsync() {
var x = await getData();
console.log(x);
}
callAsync();
(I named the function for sake of clarity, but in this scenario, one would rather use an anonymous function call; see TheReason's answer.)
or
use the result as a normal Promise, which is what an async function returns.
You have to use then with a callback:
getData().then(x => {
console.log(x);
});
The other answers have covered this fine; but I'd like to chip in and say get in the habit of creating and calling a main function rather than run things in the global scope. i.e.
async function main(){
let result = await getData();
}
main().catch(console.log);
This is pretty clear to anyone reading your code that this is your app entry point
I'm trying to return a debounced search result from an API request using lodash's debounce function but keep getting undefined from the call.
Here's my code, please help;
const searchSuggestionsRequest = async (input) => {
const params = {
userInput: encodeURIComponent(input),
};
const { data } = await axios.get(`${BASE_URL}/api/location`, { params });
return data;
};
const debouncedSuggestionsRequest = _.debounce(searchSuggestionsRequest, 500);
const fetchSearchSuggestions = (input) => {
return debouncedSuggestionsRequest(input);
};
handleSearchSuggestions = async (input) => {
const searchObj = await fetchSearchSuggestions(input);
console.log('searchObj', searchObj);
};
handleSearchSuggestions()
You are expecting the debounce function to return the result of your original function, or in your case the resolved promise. But that is not how the debounce function works.
The debounce function wraps your function with its own code in which it checks if any new call files in our not. After a certain amount of time eventually your function is initiated. But it cannot return the result of that function.
You need to define a more global scope (or at least a scope overlapping your functions) variable, and set that variable in your function where you get the axios result.
You problem remains that you cannot await for the result, so your console.log will still be undefined. Personally I develop in Vue, and I can set a reactivity watcher on the variable.
// Does not work - Cannot find name 'await'.ts(2304)
let someVariable = await (async ():someType => {
// i need to use await inside here so i need it async
return someValue;
})();
// does work, but not async.
let someVariable2 = (():someType => {
// cant use await inside
return someValue
})();
i tried wrapping await inside another set of curved brackets, still doesnt work. yes i know i can declare a function then call it like you would normally, but i'd rather have it like this. if it isnt possible then ill go back to the normal way.
i do not know fully what () does in cases like this, but im assuming it returns the object inside. is it possible to use async/await like this? if possible would also like to learn more about how () works in cases like this.
code runs on Deno
edit: people saying "await must be used inside an async block" Deno has top-level await.
Clarifying.
// this is top-level
async function somefunc() {}
await somefunc(); // this WORKS on deno.
issue is let var = await(async () => {})() creates said error, and i am trying to find a way to fix this with a other way than declaring then await it
edit: https://github.com/microsoft/TypeScript/issues/38483
await can only within an async block. Make sure outside await is also within an async block or you can save the promise within someVariable.
let someVariable = (async ():someType => {
return someValue;
})();
someVariable.then((result) => {
// result contains whatever u returned in the async block.
})
const someVariable = (async () => {
const result = await Promise.resolve('Hey there!')
return result;
})()
someVariable.then(result => console.log({ result }))
Await has to be called inside a async function.
const aFunc = async () =>{
let someVariable = await (async ():someType => {
const someValue = await asyncFunc()
return someValue;
})();
// Now you get the value
console.log(someVariable)
}
aFunc()
Now You can call aFunc function to make it work
I know this is a terrible idea. But I have an API which I can't use until I have a piece of data which I can only get asynchronously. Something like this:
const key = await get_async_data(config) // NOT RIGHT, can't use await at top level
const api = new API(key)
... use api ...
This is at top level, outside of any function, so I can't just await get_async_data() (it does return a Promise).
Is there anything short of putting all my code in a giant async function so I can call await?
API is just a class exported by a module (which I control).
(BTW I thought of putting the code to get the key into the API class's constructor, but of course constructors can't be async either.)
I could make every async method of API set the key if unset, but that's pretty invasive and error-prone.
So I'm not really asking how to make my top-level code wait as much as I'm looking for alternative ways to structure this so the async call happens cleanly.
Here's some more detail in case this helps.
In api.js:
class API {
constructor(key) {
this.key = key
// other stuff
}
async f1(a) {
}
async f2(b, c) {
}
f3() {
return true
}
}
export default API
Then in the places (many) where it'll be used:
import API from '#/api'
const key = async get_key() // NOPE
const theAPI = new API(key)
async importantMethod(args)
{
return await theAPI.f1(args)
}
async otherMethod()
{
if (theAPI.f3)
return await theAPI.f2(123)
// etc...
}
// ... and so on
Just use the Promise:
const pendingAPI = get_async_data(config).then(key => new API(key)); // N.B. no await
export default pendingAPI;
Meanwhile, in another file...
import pendingAPI from 'other/file';
pendingAPI.then(doStuffWithAPI);
There are times when async/await is a win. But never forget it's just sugar over Promises.
top level is a terrible idea, yes. But I don't see why you can't just put it in a function?
const getAsync = async () => {
const key = await get_async_data(config);
return key;
}
getAsync().then(key => {
const api = new API(key)
}
If you want to alter your existing code as little as possible, I'd consider changing the entry point to a module which gets the key, and then calls the module which instantiates the API (the old entry point). For example:
// start.js
import makeApi from './makeApi';
get_key()
.then(makeApi);
// makeApi.js
export default function(key) {
const theApi = new API(key);
function importantMethod(args) {
return theAPI.f1(args)
}
function otherMethod() {
if (theAPI.f3)
return theAPI.f2(123)
}
// etc
}
In short, all you have to do is wrap your current entry point in a function.
I want to refactor a promise chain into async/await, but Typescript is complaining about the typing.
TS2322:Type 'IHttpPromiseCallbackArg< IResp >' is not assignable to type 'IResp'...
I thought await would return a regular value, not a promise. Am I wrong? If so, how can I assign a typing so that the desired code will compile?
I thought await would return the same value as the first argument in the .then callback. Am I wrong?
Old code:
handleSubmit(form) {
const params = this.getParams(form);
this.myAsyncRequest(params)
.then((resp:IResp) => this.processResp(resp))
.catch((e:IServerError) => this.handleError(e));
}
Desired new code:
async handleSubmit(form) {
const params = this.getParams(form);
try {
const resp:IResp = await this.myAsyncRequest(params); //typing error with "const resp:IResp"
this.processResp(resp);
} catch (e:IServerError) {
this.handleError(e);
}
}
The desired code still breaks if I remove the return type in myAsyncRequest ; I guess Typescript infers directly from the AngularJS library.
myAsyncRequest(params:IParams):IHttpPromise<IResp> {
return $http.post('blah', data);
}
If I remove "IResp" from the const resp declaration, processResponse complains that IHttp< IResp> does not equal IResp...
processResp(resp:IResp) {
//do stuff
}
Your question "I thought await would return the same value as the first argument in the .then callback. Am I wrong?".
No, you are absolutely right. But you are wrong about what the first argument in the .then callback is.
You define myAsyncRequest to return IHttpPromise<IResp>. But IHttpPromise<T> is defined as inheriting IPromise the following way:
type IHttpPromise<T> = IPromise<IHttpPromiseCallbackArg<T>>;
So, an IHttpPromise<T> is a promise that returns an IHttpPromiseCallbackArg<T> back where the actual data of type T is in the data property of the IHttpPromiseCallbackArg<T>.
So, the old code variant we see in the question:
handleSubmit(form) {
const params = this.getParams(form);
this.myAsyncRequest(params)
.then((resp:IResp) => this.processResp(resp))
.catch((e:IServerError) => this.handleError(e));
}
should actually not compile without errors in TypeScript when myAsyncRequest is defined to return IHttpPromise.
Howto fix this:
async handleSubmit(form) {
const params = this.getParams(form);
try {
const httpResp:IHttpPromiseCallbackArg<IResp> = await this.myAsyncRequest(params);
const resp: IResp = httpResp.data;
this.processResp(resp);
} catch (e:IServerError) {
this.handleError(e);
}
}
Note: In the latest type definitions for angular, the type IHttpPromiseCallbackArg<T> is actually called IHttpResponse<T>.
Maybe in your code, you have defined IResp as IHttpResponse<Something>? Then you just have a conflict with the old name IHttpPromiseCallbackArg. Then get the newest type definitions from DefinitelyTyped that uses the new name. And you would also have to change the definition of myAsyncRequest to:
myAsyncRequest(params:IParams):IHttpPromise<Something> {
The line containing the await does indeed await the resolved value - but because the function itself is async (to allow all that awaiting), you get back a promise.
Example... in the below code you can use x as a plain number (even though delay returns a promise) and again for y - so all the stuff you await is resolved so you can use it more like you would if it were synchronous.
The async function that doesn't look like it returns a promise, now does.
This can seem confusing, because it seems to "invert the promises", but what it does is shift the then to the top level (you could have async functions calling down to other async functions and so on).
function delay(ms: number) {
return new Promise<number>(function(resolve) {
setTimeout(() => {
resolve(5);
}, ms);
});
}
async function asyncAwait() {
let x = await delay(1000);
console.log(x);
let y = await delay(1000);
console.log(y);
return 'Done';
}
asyncAwait().then((result) => console.log(result));