Needs the clarity about async function - javascript

I am trying to get the value from setTimeout. but console gives no result. how to handle this async functions? can any one help me to understand this in right way?
here is my try:
async function getTheme() {
const value = 'abc'
setTimeout(() => {
return value;
}, 3000);
}
getTheme().then(time => console.log(time)); //getting no result.

That is because you're returning inside the setTimeout callback, which does not actually resolve the promise.
What you want is to instead return a promise instead:
function getTheme() {
const value = 'abc'
return new Promise(resolve => {
setTimeout(() => resolve(value), 3000);
})
}
There is no need to use async, since you are already returning a promise in the getTheme() function.
Of course, you can abstract the whole "waiting" logic into another function: then, you can keep the async if you wish:
function sleep(duration) {
return new Promise(resolve => setTimeout(resolve, duration));
}
async function getTheme() {
const value = 'abc';
await sleep(3000);
return value;
}

Related

Delay before recursive function call

I'm trying to set a delay before every recursive function call. Currently, it's returning undefined. The problem might be the scope of the recursive call (inside settimeout and then).
I tried it like this:
function delay(ms) {
return new Promise(resolve => {
setTimeout(resolve, ms)
});
}
const checkIfListElementIsRendered = (className) => {
delay(10).then(function (res) {
if (document.getElementsByClassName(className)[0]) {
return true;
}
return checkIfListElementIsRendered(className);
})
}
And this:
const checkIfListElementIsRendered = (className) => {
if (document.getElementsByClassName(className)[0]) {
return true;
}
setTimeout(() => {
return checkIfListElementIsRendered(className);
}, 10);
}
Any help is appreciated!
You need to turn checkIfListElementIsRendered to async/await syntax, and await the delay and checkIfListElementIsRendered methods, Also instead return true turn it to promise to be always return a promise.
When you call checkIfListElementIsRendered method outside, you need to resolve it with await or then callback.
function delay(ms) {
return new Promise(resolve => {
setTimeout(resolve, ms)
});
}
const checkIfListElementIsRendered = async (className) => {
await delay(10)
if (document.getElementsByClassName(className)[0]) {
return Promise.resolve(true);
}
return await checkIfListElementIsRendered(className);
}

Why does this aysnc function not implicitly return a promise?

I read in this Stack Overflow question async/await implicitly returns promise? that:
"An Async function will always return a promise. If you don't
explicitly return a promise, the value you return will automatically
be wrapped in a promise."
So why does my getData2() function below return undefined?
const getData = async() => {
return new Promise(resolve => {
setTimeout(() => {
resolve('this is the data');
}, 2000);
});
};
const getData2 = async() => {
setTimeout(() => {
return 'this is the data without an explicit promise';
}, 1000);
};
(async() => {
console.log(await getData2()); // DOES NOT WORK: displays 'undefined' immediately
console.log(await getData()); // WORKS: waits one second and displays data
})();
getData2 is returning a Promise, but you're awaiting it, which extracts the resolve value from the Promise.
console.log(await getData2());
turns into
console.log(await promiseThatResolvesToUndefined);
console.log(undefined);
If you don't await it, you'll see the Promise.
const getData2 = async () => {
setTimeout(() => {
return 'this is the data without an explicit promise';
}, 1000);
};
(async () => {
console.log(getData2());
})();
The resolve value is undefined because nothing is being returned inside the body of getData2.
The issue is not with async but with using return inside an inner function (in this case a lambda), which returns from that inner function (not the outer function), and setTimeout then ignores that return value. The correct way to do this is getData (but without the async keyword which adds an second layer of Promise).

Combine async and sync function results properly

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();

Trying to understand between new Promise and Async/await

I have a very basic question:
This code
function resolveAfter2Seconds() {
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved');
}, 2000);
});
}
async function asyncCall() {
console.log('calling');
const result = await resolveAfter2Seconds();
console.log(result);
// expected output: "resolved"
}
asyncCall();
gives this output, which is correct:
> "calling"
> "resolved"
This one however:
async function resolveAfter2Seconds() {
setTimeout(() => {
return 'resolved';
}, 2000);
}
async function asyncCall() {
console.log('calling');
const result = await resolveAfter2Seconds();
console.log(result);
// expected output: "resolved"
}
asyncCall();
It gives instead:
> "calling"
> undefined
From javascript.info:
The word “async” before a function means one simple thing: a function
always returns a promise. Other values are wrapped in a resolved
promise automatically. So, async ensures that the function returns a
promise, and wraps non-promises in it
So there's something I am misunderstanding, isn't the resolveAfter2Seconds returning a promise in both scenarios (the resolveAfter2Seconds in the 2nd scenario has async)? If so why the output in the 2nd scenario?
Its a pretty basic beginner mistake you use return in an callback and expect to recevive something from the parent function
This here:
async function resolveAfter2Seconds() {
setTimeout(() => {
return 'resolved';
}, 2000);
}
Can be written to this here:
async function resolveAfter2Seconds() {
setTimeout(function() {
return 'resolved';
}, 2000);
}
And as you can see there is a second function and you return resolved to your callback function. There is actually no way to return this value like you want to, you will need to use Promises like in your first example
Since resolveAfter2Seconds doesnt return anything it will return by default undefined
No return = returns undefined
In the second case, you are not returning anything from the
resolveAfter2Seconds function, the return in the code is for the
callback of the setTimeout, which will not be returned by the
resolveAfter2Seconds function. Hence the undefined.
Both functions are returning a promise, the main differences between the two are when each promise resolves and what each promise resolves to. In your second function resolveAfter2Seconds, you're only returning inside of the setTimeout function, and as a result, you return back to the caller of the setTimeout callback function, not your resolveAfter2Seconds. Rather, your resolveAfter2Seconds doesn't return anything, and so it will implicitly return undefined which gets wrapped within a promise. It is more or less the same as writing:
function resolveAfter2Seconds() {
setTimeout(() => {
return 'resolved';
}, 2000);
return Promise.resolve(undefined);
}
function resolveAfter2Seconds() {
setTimeout(() => {
return 'resolved';
}, 2000);
return Promise.resolve(undefined); // returns a promise which resolves with the value of `undefined`
}
async function asyncCall() {
console.log('calling');
const result = await resolveAfter2Seconds();
console.log(result);
// expected output: "resolved"
}
asyncCall();
The above returns a Promise which resolves immediately with the value of undefined. As a result, you either need to explicitly wrap your setTimeout in a promise and resolve() (like your first resolveAfter2Seconds), or use something like a helper sleep method:
const sleep = n => new Promise(res => setTimeout(res, n));
async function resolveAfter2Seconds() {
await sleep(2000);
return "resolved";
}
async function asyncCall() {
console.log('calling');
const result = await resolveAfter2Seconds();
console.log(result);
// expected output: "resolved"
}
asyncCall();

Simple async await question with function returns

I have a simple yet perplexing issue with async functions.
I wish to simply return the value when its ready from the function.
Here is a sample code:
async function test() {
setTimeout(function() {
return 'eeeee';
}, 5000);
}
test().then(x => {
console.log(x)
});
You will get undefined been logged at once.
It's clear that you are trying to write a sleep() async function, but do remember that setTimeout is a sync function calling with a callback function will be executed at a given time, so while you are executing test(), the calling will run to end and return undefined as you have no return statement in the function body, which will be passed to your .then() function.
The right way to do this is to return a Promise that will be resolved after a given time, that will continue the then call.
async function sleep(time){
return new Promise((resolve,reject) => {
setTimeout(() => {
resolve("echo str")
},time)
})
}
sleep(5000).then((echo) => console.log(echo))
sleep function in short
const sleep = async time => new Promise(resolve=>setTimout(resolve,time))
With Promises
const setTimer = (duration) => {
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Done!');
}, duration);
});
return promise;
};
setTimer(2000).then((res) => console.log(res));
An async function has to return a promise. So to fix this, you can wrap your setTimeout function in a new promise like so:
async function test(){
return await new Promise((resolve, reject) => {
setTimeout(function(){
resolve('eeeee');
},5000);
})
}
test().then(x => {
console.log(x)
});
You can learn more about async/await on the MDN docs here. Hope this helps!

Categories