Async/Await returning result not promise - javascript

I'm very confused with async/await. I've been reading answers on s/o but I do not understand if async/await actually does what I want.
I'm trying to return the result of an async call in a synchronous way and maybe that's why I fail, maybe it's not made for that? I do not want to return a callback (or promise) but the result of one.
Here's what I've been trying to do
let namespace = {};
namespace.Test = class{
constructor(){
}
async get(){
let response = await this._load();
let data = await response;
console.log(data); //Logs my data but return Promise instead
return data;
}
_load(){
let promise = new Promise((resolve, reject) => {
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(function(response){
resolve(response.json());
}).catch(error => reject(error));
});
return promise;
}
}
//The goal is to figure out if I can have that
let myTest = new namespace.Test();
//Here I want data NOT a promise
let res = myTest.get();
console.log(res); //logs a Promise but I want what has been resolved instead
I thought resolving the promise inside _load and then using await inside get would do that?

I'm trying to return the result of an async call in a synchronous way
That's impossible. The only thing that is synchronously returned by an async function is a promise (all async functions return promises, by design). Async functions make the syntax for working with promises easier, but they're still asynchronous.
When you use await inside your async function, this will delay how long it takes for the returned promise to resolve. This is good: if any code is waiting on that promise, it will wait longer, and thus will hold off until your async function is completely done. But waiting for the promise is not automatic; you either need to use the promise's .then method, or need to use the await keyword inside an async function.
let resPromise = myTest.get();
resPromise.then(res => console.log(res));
async someFunction() {
const res = await myTest.get();
console.log(res);
}

as fetch() already return a promise, there is no reason to wrap it in another promise.
_load(){ return fetch('https://jsonplaceholder.typicode.com/todos/1')}

We can try this by specifying async in Self invoking function globally,
(async function() {
let namespace2 = {};
namespace2.Test = class{
constructor(){
}
async get(){
let response = await this._load();
let data = await response;
console.log(data); //Logs my data but return Promise instead
return data;
}
_load(){
let promise = new Promise((resolve, reject) => {
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(function(response){
resolve(response.json());
}).catch(error => reject(error));
});
return promise;
}
}
//The goal is to figure out if I can have that
let myTest2 = new namespace2.Test();
//Here I want data NOT a promise
let res2 = await myTest2.get();
console.log(res2);
})();

you can do this by await (see https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Operators/await)
So you just write:
//Here I want data NOT a promise
let res = await myTest.get();
And console.log(res); will now return the resolved value.

Related

Typescript: Convert For loop to Promise and wait to resolve all

ISSUE: save.emit() runs before all the iterations are completed in the below "for" loop which shows incorrect values of the addUpdate call inside loop.
I am trying to convert a for loop to promise and then wait for each of those promise to resolve so that I can emit changes and close a popup.
Below, is a test code in which I want to print "console.log("Print Before")" first for each iteration and then at the end print "console.log("Print After")" once all iterations are done.
Any help on the syntax for this is really appreciated.
convertForLoopToPromiseAndWait(someParameterOfTypeObject) {
for (var test of someParameterOfTypeObject) {
var testVariable = test.setValue;
if (testVariable) {
dataService.addUpdateEndpointCall();
console.log("Print Before");
}
}
console.log("Print After");
save.emit();
}
async addUpdateEndpointCall() {
const promise1 = this.dataService.addCall().take(1).toPromise();
const promise2 = this.dataService.deleteCall().take(1).toPromise();
await Promise.all([promise1, promise2])
.then(_ => this.save.emit());
}
Convert convertForLoopToPromiseAndWait to async method, then you can use await after for keyword and before dataService.addUpdateEndpointCall();
async convertForLoopToPromiseAndWait(someParameterOfTypeObject) {
for await (var test of someParameterOfTypeObject) {
var testVariable = test.setValue;
if (testVariable) {
await dataService.addUpdateEndpointCall();
console.log("Print Before");
}
}
console.log("Print After");
await save.emit();
}
Another way is to make a list of promises and wait for them to resolve:
const promises = [];
for await (your iterating condition) {
promises.push(dataService.addUpdateEndpointCall());
}
then use
await Promise.all(promises).then( this.save.emit());
I think that you have made a mistake here:
const promise1 = await this.dataService.addCall().take(1).toPromise();
const promise2 = await this.dataService.deleteCall().take(1).toPromise();
You await promises. The results put in the variables promise1 and promise2 will then not be promises.
Don't you mean the following?
async addUpdateEndpointCall() {
const promise1 = this.dataService.addCall().take(1).toPromise();
const promise2 = this.dataService.deleteCall().take(1).toPromise();
await Promise.all([promise1, promise2])
.then(_ => this.save.emit());
}

JavaScript: How to wait for completion of async api call

I have an async function:
const _getSelectedComponentVariantByComponentName = async (name) => {
const response = await api.get(`/internal/api/Component/GetComponentVariantByComponentName/${name}`);
componentRow.component = response.data;
return componentRow;
};
And I'm trying to use this function inside .map() method:
let componentRows = [...getState().formulaBuilder.componentRows];
componentRows = componentRows.map(async row => {
row = await _getSelectedComponentVariantByComponentName(row.name);
return row;
});
But in this case I got a Promise with status "pending".
How to wait for completion of async api call and return a value;
You can make use of Promise.all with map and use await with it.
map will return an array of Promises, Promise.all will wait for all promises to resolve and then resolve with the values as an array for each promise.
Also make sure you execute the below code in an async function:
let componentRows = [...getState().formulaBuilder.componentRows];
componentRows = await Promise.all(componentRows.map(row => {
return _getSelectedComponentVariantByComponentName(row.name);
}));

How to await on async function and collect the response

Until now, I thought await makes my program synchronous. However, I see that await only waits for async function to be resolved with a promise then the whole programs continues to run. So, what is the right way to wait & collect the response from async function?
Original code:
let result={
name:'',
country:''
};
const data = await query.getCachedData(did);
result.name = data.name; // undefined
result.country = data.country;//undefined
console.log(result);
I don't know why but awaiting on the async function result works:
let result={
name:'',
country:''
};
const data = await query.getCachedData(did);
result.name = await data.name; //'Jon'
result.country = await data.country;// 'US'
console.log(result);
But I am not sure if this is the solution.
Since getCachedData returns the promise, I thought this may be the right way but the then()/catch() didn't execute.
query.getCachedData(did).then((tfnData) => {
result.name = data.name;
result.country = data.country;
console.log(result);
}).catch((dbError) => {
console.log(dbError);
});
Can anyone correct me to get the result the right way?
A Promise is the return from a async function. The result is maybe not finish yet.
That is why you can await a method (like you did it). This will set the return from the function when the calculation is complied.
Or you can make use of 'then':
const data1 = await query.getCachedData(did);
//data1 has a value at this point of code
const data2;
query.getChachedData(did).then((result)=>{data2 = result});
//data2 can have a value or will get one later (this is async) at this point of code
With Promise all you can let multiple methods run asynchronous and wait for all at once.
https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
const callStack = [];
const data1;
const data2;
callStack.push(query.getChachedData(did).then((result)=>{data1 = result}));
callStack.push(query.getChachedData(did).then((result)=>{data2 = result}));
//run both query Methods at asynchronous
await Promise.all(callStack);
//data1 and data2 hava a value at this point of code
Until now, I thought await makes my program synchronous
Async/await makes the code to looks like synchronous, but behind is just syntactic sugar for promises in Javascript. Really? Yes
Is just return thePromise().then(result => result)
I see that await only waits for async function to be resolved with a promise then the whole programs continues to run
When you work with promises, they not make Node.js code run synchronous, in the other hand, promises allow you to write flows that appear synchronous.
So, what is the right way to wait & collect the response from async function?
According to your example, the code will be something like this:
const queryResult = did => query.getCachedData(did).then(tfnData => tfnData);
// Without async/await
queryResult(did)
.then(data => {
const { name, country } = data;
const result = { name, country };
console.log(`${result.name}, ${result.country}`); // Jon, US
})
.catch(error => console.log(`Error produced: ${error}`));
// With async/await
(async () => {
try {
// ... Some other code ....
// ... Some other code ....
// ... Some other code ....
const data = await queryResult(did);
const { name, country } = data;
const result = { name, country };
console.log(`${result.name}, ${result.country}`); // Jon, US
} catch (error) {
console.log(`Error inside try-catch: ${error}`);
}
})();
You are correct that await waits for an async function to return a promise. For your code example, I would suggest the following:
let result={
name:'',
country:''
};
async function getData() {
const data = await query.getCachedData(did);
result.name = data.name; // 'Jon'
result.country = data.country; // 'US'
console.log(result);
}
await can only be used inside an async function. It will pause the function until a promise is received from query.getCachedData(), save that response into const data which can then be used to set the name and country of the result object. You can also look at the MDN docs for both async and await.
await does not make your asynchronous code synchronous - and there should not be any reasonable reason to do so ... behind the scenes it returns a promise and chain it with then instead of you having to chain it with then yourself.
What you did with the then keyword, is what the await did for you.
You can use whatever suits you, but async/await makes your code easier to read.
if this works
result.name = await data.name;
this means that the name is an async getter function that you have to await for it to get the result. You can do it also like this
data.name.then(name => doWhateverYouWantWithName(name)) or using the await keyword like you already did - and that should be better even.

Extracting JSON from Fetch API

I realise very similar questions have been answered before, but I'm still finding it very confusing as to how this works...
From my understanding promises are used to deal with asyc requests - these promises essentially send back the state or a "promise" that at some point later a JSON body (or other object) will be delivered.
What I'm trying to understand is how I properly handle these requests so that the function doesn't return until the JSON body is ready to be parsed.
Below I'm trying to simply extract the key "result" (which returns a string "result") and parse it to another variable that can be stored and then later used somewhere else in my code. Unfortunately, my code always returns a [Object Promise], rather than the extracted JSON. I believe this is because response.json is also a promise... however, I don't understand how I get out of the "chain of promises" and return a value that I can actually do something with.
Thanks for any advice,
async function name() {
const response = await fetch('https://xxxxx.herokuapp.com/timespent', {});
const json = await response.json();
return json.result;
}
let varr = name();
console.log(varr)
Since your function is async it always return a promise. You need to use await for result.
read more about async here
async function name() {
const response = await fetch('https://mautargets.herokuapp.com/timespent', {});
const json = await response.json();
return json.result;
}
async function result(){
//await can only be called from inside of async function. So we need async function for await name()
let varr = await name();
console.log(varr) // Success
}
result()
In your example code, name function is declared async, so it returns a promise.
Inside that function body, you correctly handle async calls like fetch or the JSON transformation.
What you need now is either use await to wait for the function to "resolve", or use the "older" then/catch promises methods. Note that you cannot always use await outside an async function so you may need to wrap it.
Example :
async function name() {
const response = await fetch('https://mautargets.herokuapp.com/timespent', {});
const json = await response.json();
return json.result;
}
// using promise.then
name().then(result => console.log(result));
// wrapping await
(async function test() {
try{
console.log(await name());
}catch(error) {
// error goes here if promise got rejected
}
})()
You could have a callback in the function declaration, and use '.then(...)' and call it when the promise has been resolved:
async function name(cb) {
const response = await
fetch('https://mautargets.herokuapp.com/timespent', {});
const json = response.json();
json.then(x => cb(x))
}
name(console.log)
This is because you're using an Async function, which will return a promise.
Or if you would like the method to return, you could either call it in another Asynchronous context and utilize await again:
// Assume no callback: code just as you had it.
async function wrapper() {
console.log(await name())
}
Or you could do name().then(...) as specified before:
// Assume no callback: code just as you had it.
name().then(console.log)
Hope this helps!
I'm actually looking for the answer(same as yours), so I found this way.
I. ASK/REQUEST for data
async function fetchMyJson() {
const response = await fetch('https://1stAPI.devdeveloper1.repl.co/fiveD');
const myData = await response.json();
return myData;
}
II.GET Extract data
fetchMyJson().then(myData => {
let myData_output = myData.USD[0].rate; // fetched or Get OUTPUT data
console.log(myData_output);
document.body.innerHTML = `<div>${myData_output}</div>`; //make sure you add ${} for output
});
async function fetchMyJson() {
const response = await fetch('https://1stAPI.devdeveloper1.repl.co/fiveD');
const myData = await response.json();
return myData;
}
//GET Extract data
fetchMyJson().then(myData => {
let myData_output = myData.USD[0].rate; // fetched or Get OUTPUT data
console.log(myData_output);
document.body.innerHTML = `<div>${myData_output}</div>`; //make sure you add ${} for output
});
It is correct that you await fetch and .json since they are async.
async function name() {
const response = await fetch('http://blah.com/api', {});
const json = await response.json();
return json.result;
}
However, async and Promises inside function name make it async too. So the return value of name is a Promise that you should await it, or .then it, like:
// Old style .then
name().then(result => console.log(result))
// Modern style await
async function main() {
const result = await name()
console.log(result)
}

Async/Await not waiting for response, and returns Promise object

Using ES6, Classes, and Aync/Await...
The goal is to have an "Api" class that does async calls with fetch, and returns some data.... but even the basic foundation isn't working.
in the main js these snippet runs, which starts the chain of events:
let api = new Api();
let api_data = api.getLocation();
console.log(api_data);
getLocation method is the following, which would return some response/data. However, that data would theoretically be a fetch call to an API, which is "getTestVariable" for example that waits some time...
class Api {
getLocation = async () => {
var response = await this.getTestVariale();
console.log(response);
return response;
}
getTestVariale = () =>{
setTimeout(function(){
console.log("timeout done...");
return "this is the test variable";
},2000);
}
}
However, 1) the console.log(response) gives "undefined" because its not awaiting... and 2) back in the main js, api_data when logged, is some Promise object rather than the variable response
As the comment above states, setTimeout does not return a Promise, so getTestVariable has no return value.
Here's a slightly modified version of your code that will hopefully put you on the right track:
class Api {
getLocation = async () => {
var response = await this.getTestVariale();
console.log(response);
return response;
}
getTestVariale = () => {
return new Promise((resolve, reject) => {
if (thereIsError)
reject(Error('Error message'));
else
resolve({foo: 'bar'});
}
}
}
Drop a comment if I need to explain further I'd be happy to.
In getLocation you await for a value that will come from this.getTestVariable. In order for this to work this.getTestVariable must return a Promise; it can be done in two ways - making getTestVariable an async function or explicitly returning a Promise.
Since you're using setTimeout (which is not an async function) you're bound to use Promise. Here you go:
class Api {
async getLocation() {
return await this.getTestVariable();
}
getTestVariable() {
return new Promise((res, rej) => {
setTimeout(() => res('test'), 2000)
});
}
}
async function main() {
let api = new Api;
console.log('Trying to get the location...');
console.log('Voila, here it is: ', await api.getLocation());
}
main();
Looks quite ugly but there's no way you can achieve it if you use set timeout.
The main point is in resolution of getTestVariable with value you want it to return.
Quite an important remark: you can mark getTestVariable as an async function, it will ad an extra Promise level, but you still will have the desired result.

Categories