Can anyone please help me with the following, I am new to Async\Await in Javascript:
I have a trivial class:
function Thing()
{
}
Thing.prototype.ShowResult = function ()
{
var result = this.GetAsync();
alert(result);
}
Thing.prototype.GetAsync = async function ()
{
var result = await this.AsyncFunc();
return result;
}
Thing.prototype.AsyncFunc = async function ()
{
return new Promise(resolve => {
setTimeout(() => {
resolve(6);
}, 2000);
});
}
I call it like this:
var thing = new Thing();
thing.ShowResult();
I expected a delay of 2 seconds before seeing the result of 6.
Instead I immediately see:
[object Promise]
How can I correctly await the result? Thanks for any help.
You have to make the parent function consuming the async function async as well.
function Thing() {}
Thing.prototype.ShowResult = async function() { // add async
var result = await this.GetAsync(); // await the response
alert(result);
}
Thing.prototype.GetAsync = async function() {
var result = await this.AsyncFunc();
return result;
}
Thing.prototype.AsyncFunc = async function() {
return new Promise(resolve => {
setTimeout(() => {
resolve(6);
}, 2000);
});
}
Then you can call ShowResult
var thing = new Thing();
await thing.ShowResult();
But, if you're calling thing.ShowResult outside of an async function you'll have to use the Promise syntax since you can't await something that isn't in an async function. There's no concept of a "top level await" in JS. Yet.
var thing = new Thing();
thing.ShowResult().then( result => console.log(result) );
In JavaScript, async functions always return a Promise (this is why you see [object Promise]), which can be resolved either by calling its then method or by using the await keyword. For now, await can only be used inside async functions.
To apply this to your problem, you can do one of the following:
#1
Thing.prototype.ShowResult = function ()
{
this.GetAsync().then(alert);
}
thing.ShowResult();
#2
In this approach, ShowResult is also an async function. So what I wrote above also applies to it.
Thing.prototype.ShowResult = async function ()
{
var result = await this.GetAsync();
}
await thing.ShowResult();
Though AsyncFunc and GetAsync are async functions. ShowResult function is not. It is necessary for the parent function to be async as well. The below code returns 6.
function Thing()
{
}
Thing.prototype.ShowResult = async function ()
{
var result = await this.GetAsync();
alert(result);
}
Thing.prototype.GetAsync = async function ()
{
var result = await this.AsyncFunc();
return result;
}
Thing.prototype.AsyncFunc = async function ()
{
return new Promise(resolve => {
setTimeout(() => {
resolve(6);
}, 2000);
});
}
var thing = new Thing();
thing.ShowResult();
Your function GetAsync() return a promise to consume the promise you have to either use await or .then read more about async/await
function Thing() {}
Thing.prototype.ShowResult = async function() {
var result = await this.GetAsync();
alert(result);
}
Thing.prototype.GetAsync = async function() {
var result = await this.AsyncFunc();
return result;
}
Thing.prototype.AsyncFunc = async function() {
return new Promise(resolve => {
setTimeout(() => {
resolve(6);
}, 2000);
});
}
var thing = new Thing();
thing.ShowResult();
using .then
function Thing() {}
Thing.prototype.ShowResult = async function() {
var result = this.GetAsync().then((result)=>alert(result));
}
Thing.prototype.GetAsync = async function() {
var result = await this.AsyncFunc();
return result;
}
Thing.prototype.AsyncFunc = async function() {
return new Promise(resolve => {
setTimeout(() => {
resolve(6);
}, 2000);
});
}
var thing = new Thing();
thing.ShowResult();
Related
I try to combine two function values (from a() and b()), but the code is not waiting on the await-statement in function test as expected. Instead the result value prints directly the wrong result.
function resData(status, message) {
return { ok: status, message: message };
}
function a() {
return resData(true, 'A');
}
async function b() {
// simulate some long async task (e.g. db call) and then return the boolean result
function sleep(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
}); }
await sleep(2500);
return resData(true, 'B');
}
async function isValid() {
const promises = [a, b].map(async (fnc) => { return await fnc().ok; });
const results = await Promise.all(promises);
// combine the results to one boolean value
return results.every(Boolean);
}
async function test() {
// not waiting here
const res = await isValid();
// prints directly - wrong result false
console.log('result', res);
}
test();
After the wrong result output it waits 2.5 seconds. I think it has to do with the function call of resData, but I couldn't figure it out by myself, where my async / await misunderstanding is. Thanks in advance.
Instead of awaiting for the function to be resolved, You are awaiting on value return by function.
async function isValid() {
const promises = [a, b].map(async (fnc) => {
//return await fnc().ok;
// You have to await first function then call `.ok` value
return (await fnc()).ok;
});
const results = await Promise.all(promises);
// combine the results to one boolean value
return results.every(Boolean);
}
Just to simplify the problem, Please check the below code.
async function test() {
return { ok: true };
}
async function main() {
// trying to await on undefined.. test().ok == undefined
console.log(await test().ok); // undefined
// first await function.. then return ok
console.log((await test()).ok); // true
}
main();
I'd say there is 2 1 problem with your code
a was not returning a promise, so you cant treat it as one - ignore turns out you can, who knew!
You cant await a boolean, so await fnc().ok made no sense.
I would suggest you
Make a return a promise even if its just a resolved promise
Execute just the methods in the map
Read the value of ok within the every call to determine if all promises resolved with this value set to true
With these changes, it works how I suspect you expected with a 2.5 second wait before writing to the console.
function resData(status, message) {
return { ok: status, message: message };
}
function a() {
return resData(true, 'A');
}
async function b() {
// simulate some long async task (e.g. db call) and then return the boolean result
function sleep(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
}); }
await sleep(2500);
return resData(true, 'B');
}
async function isValid() {
const promises = [a, b].map(fnc => fnc());
const results = await Promise.all(promises);
// combine the results to one boolean value
return results.every(x => x.ok);
}
async function test() {
// not waiting here
const res = await isValid();
// prints directly - wrong result false
console.log('result', res);
}
test();
Async functions implicitly return a promise that will ultimately be resolved to the final value returned when the function execution ends.
So, you just need to call your functions inside your map callback to collect the promises. The array of results will be an array of resData objects. So, you finally check for each ok property to match your requirements.
function sleep(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
function resData(status, message) {
return {ok: status, message: message};
}
function a() {
return resData(true, 'A');
}
async function b() {
await sleep(2500);
return resData(true, 'B');
}
async function isValid() {
const promises = [a, b].map((fnc) => fnc());
const results = await Promise.all(promises);
return results.every((result) => result.ok);
}
async function test() {
const res = await isValid();
console.log('result', res);
}
test();
I have this piece of code which is inside a function that is called by another second function. Now I have no clue, how to return the result to the second function.
(async () => {
try {
const response = await axios.get(knockoutCityURL);
console.log(response.data["1301210"].data.price_overview);
} catch (error) {
console.log(error.response.body);
}
})();
I would be very happy if you could help me.
Remove the IIFE, and just return the Axios promise from a simple function, then make your second function async, and await the data.
(Here's a JSFiddle as async/await doesn't work in a snippet)
function fn1() {
// return axios.get(knockoutCityURL);
return new Promise((res, rej) => {
setTimeout(() => res('Hallo'), 2000);
});
}
async function fn2() {
const data = await fn1();
console.log(data);
}
fn2();
let myObject = ( () => {
let run = async() => {
foo = new genericFunction();
status = await foo.myFunction();
}
})();
Another FIle.js
let genericFunction = function() {
this.getData = async () => {
$.getJSON("path/to/file.json", function (data) {
console.log("Apple", data.name);
return data.name;
}).fail(function(jqxhr, textStatus, error){
console.log("Loading Error :: ", error);
)};
}
this.myFunction = async () => {
let data = this.getData();
console.log('DATAA:::', data); //This should be the first output
}
}
The problem is:
status is always = undefined because somehow it returns before getJSON executes and I don't know why.
Another FIle.js should be like:
let genericFunction = function() {
this.getData = async () => {
var result = await $.getJSON("path/to/file.json", function (data) {
console.log("Apple", data.name);
return data.name;
}).catch(function(jqxhr, textStatus, error){
console.log("Loading Error :: ", error);
)};
return result;
}
this.myFunction = async () => {
let data = this.getData();
console.log('DATAA:::', data); //This should be the first output
}
}
Here's a simplified example using your code but with a couple of changes:
1) Uses a class
2) You're not returning anything from myFunction so there's no reason to assign something to status - just call the function.
3) getData doesn't need an async keyword, and you need to return the promise (in this example I mocked up a AJAX call that returns data after a second) from the function for it to work.
4) You do need to await for the promise to return in myFunction. You have async there, you just need to add the await keyword too.
class GenericFunction {
getData() {
return new Promise(resolve => {
setTimeout(() => resolve('Hello World'), 2000);
});
}
async myFunction() {
let data = await this.getData();
console.log('DATAA:::', data);
}
}
(async () => {
const foo = new GenericFunction();
foo.myFunction();
})();
Functions that are called with call or apply using await never resolve, please check the following code snippet
const obj = {
resolveAfter2Seconds: function() {
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved');
}, 2000);
});
}
}
async function asyncCall() {
console.log('calling');
var result = await obj.resolveAfter2Seconds();
console.log(result);//resolved
var result2 = await obj.call("resolveAfter2Seconds");
console.log(result2);//never alled
}
asyncCall();
Just expanding #CertainPermances comment - call is a function method used to assign an option to this inside the function, you can't use it on an object
(function() {
const obj = {
resolveAfter2Seconds : function() {
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved');
}, 2000);
});
}
}
async function asyncCall() {
console.log('calling');
var result = await obj.resolveAfter2Seconds();
console.log(result);//resolved
// var result2 = await obj.call("resolveAfter2Seconds"); caused an eror
var result2 = await obj.resolveAfter2Seconds();
// or
var result2 = await obj.resolveAfter2Seconds.call( obj /* perhaps */); // which makes no difference at all because this = obj anyway
console.log(result2);
}
asyncCall();
})();
I was asking the question in wrong way, I ended up using the correct syntax as follows
const obj = {
resolveAfter2Seconds: function() {
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved');
}, 2000);
});
}
}
async function asyncCall() {
console.log('calling');
var result = await obj.resolveAfter2Seconds();
console.log(result);//resolved
var result2 = await obj["resolveAfter2Seconds"].call();
console.log(result2);//never alled
}
asyncCall();
If I have this two variables with setTimeouts:
var printOne = setTimeout(function() {
console.log("one!");
}, 500);
var printTwo = setTimeout(function() {
console.log("two!");
}, 50);
it's just for example. What I want is, to make a function(with async and await that will call the above variables, but in order. Like this:
theFunction(printOne, printTwo);
// Will output:
// one!
// two!
To accomplish that with async functions, you need to work along with promises.
An alternative is wrapping both setTimeout calls into a function which returns a promise:
var printOne = function() {
return new Promise(function(resolve) {
setTimeout(function() {
console.log("one!");
resolve();
}, 500);
})
}
var printTwo = function() {
return new Promise(function(resolve) {
setTimeout(function() {
console.log("two!");
resolve();
}, 50);
})
}
function theFunction(one, two) {
}
async function main() {
theFunction(await printOne(), await printTwo());
}
main();
Create a function that return promise which encapsulate setTimeout
var fnPromiseTimeout = async function(msg, time) {
return new Promise( (resolve) => setTimeout( () => {
//console.log(msg);
resolve(msg);
}, time ) );
};
Demo
var fnPromiseTimeout = async function(msg, time) {
return new Promise( (resolve) => setTimeout( () => {
//console.log(msg);
resolve(msg);
}, time ) );
};
async function f1(timer1, timer2)
{
console.log("start");
var a = await timer1;
console.log(a);
var b = await timer2;
console.log(b);
console.log("end");
}
f1(fnPromiseTimeout("one", 500), fnPromiseTimeout("two", 500));