I'm trying async/await functionality. I have such code imitating a request:
const getJSON = async () => {
const request = () => new Promise((resolve, reject) => (
setTimeout(() => resolve({ foo: 'bar'}), 2000)
));
const json = await request();
return json;
}
When I use the code in this way
console.log(getJSON()); // returns Promise
it returns a Promise
but when I call this line of code
getJSON().then(json => console.log(json)); // prints { foo: 'bar' }
it prints json as expected
Is it possible to use just code like console.log(getJSON())? What don't I understand?
Every async function returns a Promise object. The await statement operates on a Promise, waiting until the Promise resolves or rejects.
So no, you can't do console.log on the result of an async function directly, even if you use await. Using await will make your function wait and then return a Promise which resolves immediately, but it won't unwrap the Promise for you. You still need to unwrap the Promise returned by the async function, either using await or using .then().
When you use .then() instead of console.logging directly, the .then() method makes the result of the Promise available to you. But you can't get the result of the Promise from outside the Promise. That's part of the model of working with Promises.
A function defined with async always returns a Promise. If you return any other value that is not a Promise, it will be implicitly wrapped in a Promise. The statement const json = await request(); unwraps the Promise returned by request() to a plain object { foo: 'bar' }. This is then wrapped in a Promise before being returned from getJSON so a Promise is what you ultimately get when you call getJSON(). So to unwrap it, you can either call getJSON().then() like you've done or do await getJSON() to get the resolved value.
Return value of an async function will always be an AsyncFunction Object, which will return a Promise when called. You can not change that return type. The point of async/await is to easily wait for other async process to complete inside an async function.
const getResOrErr = () => {
const callAsyncCodeHere = async () => {
const request = () =>
new Promise((resolve, reject) =>
setTimeout(() => resolve({ foo: "bar" }), 2000)
);
const json = await request();
return json;
};
return callAsyncCodeHere()
.then(console.log)
.catch(console.log);
};
getResOrErr();
Try this. You can achieve making a function inside your main function and then put you promise code inside that function. Call it there and when you get the response or error just return it.
Related
I'm trying async/await functionality. I have such code imitating a request:
const getJSON = async () => {
const request = () => new Promise((resolve, reject) => (
setTimeout(() => resolve({ foo: 'bar'}), 2000)
));
const json = await request();
return json;
}
When I use the code in this way
console.log(getJSON()); // returns Promise
it returns a Promise
but when I call this line of code
getJSON().then(json => console.log(json)); // prints { foo: 'bar' }
it prints json as expected
Is it possible to use just code like console.log(getJSON())? What don't I understand?
Every async function returns a Promise object. The await statement operates on a Promise, waiting until the Promise resolves or rejects.
So no, you can't do console.log on the result of an async function directly, even if you use await. Using await will make your function wait and then return a Promise which resolves immediately, but it won't unwrap the Promise for you. You still need to unwrap the Promise returned by the async function, either using await or using .then().
When you use .then() instead of console.logging directly, the .then() method makes the result of the Promise available to you. But you can't get the result of the Promise from outside the Promise. That's part of the model of working with Promises.
A function defined with async always returns a Promise. If you return any other value that is not a Promise, it will be implicitly wrapped in a Promise. The statement const json = await request(); unwraps the Promise returned by request() to a plain object { foo: 'bar' }. This is then wrapped in a Promise before being returned from getJSON so a Promise is what you ultimately get when you call getJSON(). So to unwrap it, you can either call getJSON().then() like you've done or do await getJSON() to get the resolved value.
Return value of an async function will always be an AsyncFunction Object, which will return a Promise when called. You can not change that return type. The point of async/await is to easily wait for other async process to complete inside an async function.
const getResOrErr = () => {
const callAsyncCodeHere = async () => {
const request = () =>
new Promise((resolve, reject) =>
setTimeout(() => resolve({ foo: "bar" }), 2000)
);
const json = await request();
return json;
};
return callAsyncCodeHere()
.then(console.log)
.catch(console.log);
};
getResOrErr();
Try this. You can achieve making a function inside your main function and then put you promise code inside that function. Call it there and when you get the response or error just return it.
I'm given a code with 3 parts that must not be changed:
1. a call to getData function, and then prints the output.
getData().then(console.log);
2. The function signeture:
async getData(): Promise<string[]>
3. function getDataFromUrl
function getDataFromUrl(url: string, callback: any) {
fetch(URL)
.then((content: any) => content.json())
.then((data) => callback(data));
}
This is my implementation for getData function:
async getData(): Promise<string[]> {
return await new Promise<any>(function(resolve, reject) {
resolve(getDataFromUrl(myUrl, ((data: string[]): string[]=> {
return data
})))
});
}
The problem is that the code after fetch, runs after
getData().then(console.log);
so console.log prints: undefined
What do I need to change in the getData function?
Thanks
Instead of resolving the getDataFromUrl function, you should resolve the value that the callback function exposes.
getData(): Promise<string[]> {
return new Promise<string[]>(function(resolve, reject) {
getDataFromUrl(myUrl, (data: string[]): string[] => {
resolve(data)
})
});
}
It's unfortunate you can't change anything about the other functions, because returning the promise created by fetch in your getDataFromUrl function, would make the code way better, as Quentin demonstrates.
getDataFromUrl doesn't have a return value, so it returns undefined.
So you pass undefined to resolve (which resolves your other promise) and then, later the promise created by getDataFromUrl (or rather fetch) resolves.
Don't create bonus promises
Don't mix callbacks and promises
Just return the promise from fetch.
function getDataFromUrl(url: string, callback: any) {
return fetch(URL)
.then((content: any) => content.json());
}
And use that promise instead of creating a new one in getData (which doesn't need to use await because that will just resolve the promise which will immediately get wrapped in a new promise by async.
getData(): Promise<string[]> {
return getDataFromUrl(myUrl);
}
function getDataFromUrl(url, f) {
// call fetch (returns promise) but we can use then as well.
// note our callback: f where we pass the data to the callback.
fetch(url).then((content) => content.json()).then(data => f(data));
}
// edit: note we don't need this be async anymore...
async function getData() {
// create a promise...
return new Promise((resolve, reject) => {
// we call with callback arrow and resolve data here
getDataFromUrl('https://randomuser.me/api/', (data) => resolve(data));
})
}
// we print the data once the getData is done fetching
// you can also use reject to handle anything that goes wrong in above.
getData().then(data => console.log(data));
Resources used:
Fetch API
Async, Await, and Promise
Callback
This question already has answers here:
async/await implicitly returns promise?
(5 answers)
Closed 1 year ago.
When I console.log(data), I log the information I need, but if return the value of data in getWeather(), it just returns a pending promise. I have tried many things, but none have worked so far. I'll leave my broken code below.
const axios = require('axios');
const getWeather = async () => {
try {
let response = await axios.get(
'http://api.openweathermap.org/data/2.5/forecast?id=524901&appid={apiKey}'
);
let data = response.data;
return data;
} catch (e) {
console.log(e);
}
};
async function returnAsync() {
const x = await getWeather();
return x;
}
console.log(getWeather()); // returns a pending promise
console.log('check ', returnAsync()); // also returns a pending promise
async functions must return a promise. (they implicitly return Promise<void> instead of void!)
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.
For example, the following:
async function foo() {
return 1
}
...is equivalent to:
function foo() {
return Promise.resolve(1)
}
Source
This could be to do with the fact that you're trying to call an async function inside of a synchronous function. It's quite a common mistake to make, so don't fret. Typically if you think about the structure, the console logs could technically be run before the async function has completed. That's why we have "callback functions" which basically just run as soon as the async returns a value.
Axios has a really neat way to use these callbacks which is just using the .then() function.
So try this out and see if it works:
const axios = require('axios');
const getWeather = async () => {
axios.get('http://api.openweathermap.org/data/2.5/forecast?id=524901&appid={apiKey}')
.then(json => console.log(json))
.catch(error => console.log(error))
};
getWeather();
Because you're trying to call the get request inside of an async function, you cannot then grab the data in a synchronous function.
//const getWeather = async () => {...
An async function's return value will be a Promise which will be resolved with the value returned by the async function, or rejected with an exception thrown from, or uncaught within, the async function.
check more at
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
I am looking to return an array in a promise but it keeps saying promise pending. It is returning promise: fulfilled and promise value: array. I have read the documentation and the thread on here about promises and have tried to use it as a function. I have tried to use async await but nothing seems to be working. I read somewhere that you can store it in a global variable, is that the case. Or is you can't store it in a global variable when you use React, because I am using React. Can someone point me in the right direction?
Here's my code:
const currentSymbol = fetch(`https://finnhub.io/api/v1/stock/symbol?exchange=US&token=${key}`)
.then((res) => {
return res.json();
}).then((results) => {
return results.map(result => {
return result
})
})
console.log(currentSymbol)
How about this beautiful await / async implementation ?
function currentSymbol(){
return new Promise(function(resolve){
fetch(`https://finnhub.io/api/v1/stock/symbol?exchange=US&token=${key}`)
.then((res) => {
resolve( res.json());
})
});
}
Then get result with:
let result = await currentSymbol();
The issue is that you are logging a Promise object which is awaitable. To execute the Promise and get its actual result you need to make use of either .then() or await implementation on the Promise object itself
I have a function which makes an XMLHttpRequest and returns a promise with the response from the request.
However I'd like to instead return a promise which contains just one string from the response.
E.g instead of the promise resolving to response = {status, data} etc, I'd like to return just response.data.some_field
How can I do this?
If you call .then on a promise, you'll produce another promise which will resolve to whatever you return in the callback function. So take the current promise that you're creating, and then add on the following:
.then((response) => {
return response.data.some_field;
});
So maybe the full function will look like this:
function getStuff() {
return new Promise((resolve, reject) => {
//somethingWithXMLHttpRequest
}).then((response) => {
return response.data.some_field;
});
}
What you're looking for is promise chaining. Link goes to mozilla's doc page on promise chaining.
function httpRequestAsync () {
// Return a promise... This is where your XMLHttpRequest takes place
}
function getStuffAsync() {
// Make your http request, chain the return promise,
// and return a promise, which resolves to the chosen field.
return httpRequestAsync() //Calling .then() on this promise is promise chaining.
.then((response) => {
return response.data.some_field;
});
}
function someBusinessLogicFunction () {
let yourString = "";
getStuffAsync()
.then((response) => {
yourString = response; // yourString does in fact equal the response param... :).catch(() => {
console.log("Something went wrong, or this answer sucks ha ha!");
});
})
}
// Or using async/await, for fun
async someBusinessLogicFunction2 () {
let yourString = "";
try {
yourString = await getStuffAsync();
} catch (e) {
console.log("Something went wrong, or this answer sucks ha ha!");
}
}
My example splits out your HTTP request into one function, with another function declared, which calls that function, and performs the promise chaining. You could omit the second function, and return the chained promise from the function that performs the HTTP request.
You have something like this (got it from your code block before you edited the question)
const promise = axios
.post(url("fistbump"), data)
.then(result => {
window.console.log("Got fistbump response: ", result.data);
localStorage.setItem(ACCOUNT_TOKEN_FIELD, result.data.key);
});
return promise;
If the Axios promise respects the ES6 promise spec, you can simply return what you want from the .then clause to get the value wrapped in a promise, which gives you
const promise = axios
.post(url("fistbump"), data)
.then(result => {
window.console.log("Got fistbump response: ", result.data);
localStorage.setItem(ACCOUNT_TOKEN_FIELD, result.data.key);
return result.data;
});
return promise;