How to call async function from sync function - javascript

How to call async function from regular sync function?
getCategoryAll() doesn't work on page load as it works correctly when I type it into console.
What I should change to make my function call giving an output that I expect?
async function getCategory(catId) {
const response = await axios.get...
// my code here
}
function getCategoryAll() {
// my for loop logic here referring to getCategory(catId)
}
getCategoryAll()
Right now solution what I have is delaying execution of 2nd function which is obviously not the best solution
setTimeout(() => getCategoryAll(), 500);

Related

What is the difference between JavaScript async/await and Synchronous JavaScript?

JavaScript async/await and Synchronous JavaScript both look similar and making the program to wait, then what is the use of async/await ?
For example
Synchronous JavaScript Code
function getStudentList() {
return ['Adam', 'Ben'];
}
function findStudent(who) {
const list = getStudentList();
const found = list.some(student => student === who);
console.log(found); // logs true
}
findStudent('Adam');
Asynchronous JavaScript using async/await
function getStudentList() {
return new Promise(resolve => {
setTimeout(() => resolve(['Adam', 'Ben'], 1000);
});
}
async function findStudent(who) {
const list = await getStudentList();
const found = list.some(student => student === who);
console.log(found);
}
findStudent('Adam');
in above code, const list = getStudentList(); and const list = await getStudentList(); both functions like synchronous code.
Thank you
A synchronous function/code is a code that gets executed line by line, task by task. No matter how much time a specific task takes to be executed the next one doesn't start until the current one is finished, in other words the execution flow is paused/stopped in each task and starts back again when the current task is finished. i.e:
console.log("foo");
console.log("bar");
// executing this code will log the following:
// foo
// bar
An asynchronous function/call is a code that starts executed at a certain point in time and then the next tasks get executed even if the first one is not finished. So it gets executed in, say, a parallel timeline or thread if you want to call it.
An example of this would be having a function that logs "ASYNC" after 3 seconds (suppose we have a pre-defined delay function called sleep(seconds)):
async function foo() {
sleep(3); // wait for 3 seconds
console.log("ASYNC");
}
console.log("foo");
foo();
console.log("bar");
// executing this code will log the following:
// foo
// bar
// ASYNC
Note that bar was logged before ASYNC even though the function that logs the latter was called first. Basically asynchronous function don't stop the execution flow and just start executing the code inside it and goes on to the next line of code after the call, regardless of whether the async code was finished or not.
There are times when you actually want the execution flow to stop in asynchronous code. Say you have a variable called x and you want to have a sum operation function called calculate() and its result is stored to x but the function is an online request that is executed with a certain amount of delay (for example, 1 second).
let x = 0;
async main() {
console.log(x);
x = calculate(5,8);
console.log(x);
}
main();
// executing this code will log the following:
// 0
// {}
Note that the value of x didn't become 13 as expected but we got some weird result instead. This is because the request started executing and then the value of x was logged before the request has returned the sum, as a result (and depending on how a the request works) the value of x will be some random object or null/undefined until the request is finished and then x will be equal to 13
To fix this, we have to use the keyword await that stops the asynchronous execution flow and waits for another asynchronous function to end until the flow is back on.
let x = 0;
async main() {
console.log(x);
x = await calculate(5,8);
console.log(x);
}
main();
// executing this code will log the following with a 1 second delay between each log:
// 0
// 13
Side note: the await keyword cannot be used in synchronous context like
await someAsyncFunction();
and is only used before asynchronous functions (the ones that are defined with the async keyword).So await is only used with asynchronous functions in asynchronous contexts like this:
async someAsyncFunction() {
// some tasks
await anotherAsyncFunction();
// some more tasks
}
Your first example is synchronous. It's also faster.
function getStudentList(){
return ['Adam', 'Ben'];
}
function findStudent(who){
const list = getStudentList(), found = list.includes(who);
console.log(found); // logs true
}
console.time('sync'); findStudent('Adam'); console.timeEnd('sync');
Your second example is asynchronous, and slower by about a second. But, you wouldn't be able to test that, unless your async function is resolved first. That's why I used .then.
function getStudentList(){
return new Promise(resolve=>{
setTimeout(() => resolve(['Adam', 'Ben']), 1000);
});
}
async function findStudent(who){
const list = await getStudentList(), found = list.includes(who);
console.log(found);
}
console.time('async');
findStudent('Adam').then(()=>{
console.timeEnd('async');
});
You will notice that arrayInstance.includes is a better solution to find if something is in an Array. By the way, it makes no sense to use async in this particular case.
Here is an async example that makes more sense:
function delay(milliseconds){
return new Promise(resolve=>{
setTimeout(()=>{
resolve(milliseconds);
}, milliseconds);
});
}
async function logicalAsync(){
let wait;
console.time('test');
wait = await delay(1000);
console.timeEnd('test');
console.log('milliseconds = '+wait);
}
logicalAsync();
Of course, synchronous code takes however long it takes to execute, with all the code below it waiting on the above code to be finished processing. Asynchronous code allows the code below to execute (possibly) before the code above it is finished.

Behind the scene- If I use Aync but doesn't use await in it, would it be identical with normal function? [duplicate]

This question already has answers here:
Async function without await in JavaScript
(4 answers)
Closed 2 years ago.
due to everyone's help, I got the logic behind async, promise, then, await.
I have one curisosity on top of its basic nature, which is what if
I declare async function but doesn't use await in it.
technically every argument within async function is invisibly capsulated by '.then()'
but how it works would be exactly same as synchronous function execution.
For example,
async function trackUserHandler() {
var positiondata= await getPosition();
var timerdata = await setTimer(2000)
console.log(positiondata, timerdata);
setTimer(1000).then(() => {
console.log('Timer done!');
});
console.log('one');
}
The console below doesn't run till the first two await function is done due to await(s) sitting before this.
console.log(positiondata, timerdata);
What if I don't put any await(s) in the async like below?
async function trackUserHandler() {
var positiondata= getPosition();
var timerdata = setTimer(2000)
console.log(positiondata, timerdata);
setTimer(1000).then(() => {
console.log('Timer done!');
});
console.log('one');
}
I test-run this code and behaves seemigly same as regular function without 'async'.
Of course behind the scene, everything in the function is encapsulated into 'then()' though.
Am I understanding right?
Thank you in advance.
Behind the scene- If I use Aync but doesn't use await in it, would it be identical with normal function?
Yes, you are right. An async function without an await expression will run synchronously and would be identical with normal function, but the only difference is that 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)
}
If there is an await expression inside the function body, however, the async function will always complete asynchronously.
For example:
async function foo() {
await 1
}
...is equivalent to:
function foo() {
return Promise.resolve(1).then(() => undefined)
}
Code after each await expression can be thought of as existing in a .then callback.
Yes, an async function runs synchronously till the first await, so it behaves like a regular function. It does return a Promise though:
function trackUserHandler() {
// ... code
return Promise.resolve(undefined);
}
In your example, the 2 functions won't behave the same. Without the await keyword, your variables won't capture the results returned by these 2 functions, but instead receive 2 Promises.
var positiondata = getPosition();
var timerdata = setTimer(2000);
So your console.log will print out 2 Promises instead of the values you actually expect.
An async function can contain an await expression, that pauses the
execution of the async function and waits for the passed Promise's
resolution, and then resumes the async function's execution and
returns the resolved value.
As you assumed, if no await is present the execution is not paused and your code will then be executed in a non-blocking manner.
const getPromise = async (s) => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(s), 500);
});
}
(async() => {
try {
const result = getPromise("a"); //no await, result has not been unwrapped
console.log('async/await -> ', result);
} catch (err) {
console.log(err);
}
})();
Async function without await in Javascript

Repeat async function indefinitely without recursion/Promise

I want to repeatedly call an async function once it completes execution.
The async function invokes its callback argument upon completion, so I can accomplish this by recursively calling the function with the callback:
const fn = () => asyncFn(fn);
However, since NodeJS has stopped supporting tail call optimization, this method will eventually cause stack overflow.
A better way is to use ES6 Promise:
async function fn() {
while (true) {
await new Promise(asyncFn);
}
}
Is there any other way to do it? How would it be done before the introduction of Promise?
I think your initial assumption about the recursive function is incorrect. When you call an async function the callback is queued and the function continues and returns. Once the async function resolves the function is called again, but this is after it has already returned so the stack doesn't wind up.
You can see that here where we get the start and end of the function:
const runAsync = () => {
console.log("starting async function")
setTimeout(() => {
let v = runAsync()
console.log("return val", v)
}, 1000)
return "async function return"
}
console.log("return: ", runAsync())
If the stack was winding up with this, you would never see the return value. You would just see the logs starting async function for each call. This is the behavior seen here where the stack does overflow:
const recursiveFn = () => {
console.log("starting function")
let v = recursiveFn()
console.log("return val", v)
return "test" // never gets here
}
console.log("return: ", recursiveFn())

JS Event Handler: async function

I'm building an app with Cordova. On one page, there is an EventListener that calls an async function. window.addEventListener("load", loadEdit(), false);
The function looks like this async function loadEdit(){...}.
When testing in the browser I get the following error even though the function is fully executed:
TypeError: Property 'handleEvent' is not callable.
However, if I change the EventListener to another function which then calls the async function, there seems to be no problem.
For example:
window.addEventListener("load", loadPre(), false);
...
function loadPre()
{
loadEdit();
}
What is the problem with an async function getting called by the EventListener?
Why does it not detect that the second method also calls an async function?
You can call an async function from your EventListener.
The first problem I see is that you are invoking the callback function right away in the second argument of window.addEventListener by including it as loadEdit() instead of loadEdit or () => loadEdit(). You have to give it a function as second argument, right now you are giving a Promise or the return value of loadPre().
Try this way:
window.addEventListener("load", () => loadEdit(), false);
async function loadEdit() {
// do the await things here.
}
Async function return Promises. So, if you would like to do something after loadEdit, try:
window.addEventListener("load", () => {
loadEdit().then(/* callback function here */);
}, false);
async function loadEdit() {
// do the await things here.
}
TL&DR: In order to use a call-back with an async function, you will need to decorate your async function within the Add Listener, and use await within the code block;
Explanation: As mentioned above in your example you are calling the function immediately; This means either two things will happen: Your function will return a value immediately OR you will get a promise; In either case its best to 'await' the call so the program runs more synchronously.
async function getStringSize(searchString) {
return searchString.length;
}
txtInput.addEventListener("keyup", async e => {
const searchString = e.target.value;
total_length = await getStringSize(searchString);
if (total_length > 3) {
console.log(searchString);
}
}, false);

async function - await not waiting for promise

I'm trying to learn async-await. In this code -
const myFun = () => {
let state = false;
setTimeout(() => {state = true}, 2000);
return new Promise((resolve, reject) => {
setTimeout(() => {
if(state) {
resolve('State is true');
} else {
reject('State is false');
}
}, 3000);
});
}
const getResult = async () => {
return await myFun();
}
console.log(getResult());
why am I getting output as -
Promise { <pending> }
Instead of some value? Shouldn't the getResult() function wait for myFun() function resolve it's promise value?
If you're using async/await, all your calls have to use Promises or async/await. You can't just magically get an async result from a sync call.
Your final call needs to be:
getResult().then(response => console.log(response));
Or something like:
(async () => console.log(await getResult()))()
What you need to understand is that async/await does not make your code run synchronously, but let's you write it as if it is:
In short: The function with async in front of it is literally executed asynchronously, hence the keyword "async". And the "await" keyword wil make that line that uses it inside this async function wait for a promise during its execution. So although the line waits, the whole function is still run asynchronously, unless the caller of that function also 'awaits'...
More elaborately explained: When you put async in front of a function, what is actually does is make it return a promise with whatever that function returns inside it. The function runs asynchronously and when the return statement is executed the promise resolves the returning value.
Meaning, in your code:
const getResult = async () => {
return await myFun();
}
The function "getResult()" will return a Promise which will resolve once it has finished executing. So the lines inside the getResult() function are run asynchronously, unless you tell the function calling getResult() to 'await' for it as well. Inside the getResult() function you may say it must await the result, which makes the execution of getResult() wait for it to resolve the promise, but the caller of getResult() will not wait unless you also tell the caller to 'await'.
So a solution would be calling either:
getResult().then(result=>{console.log(result)})
Or when using in another function you can simply use 'await' again
async function callingFunction(){
console.log(await(getResult());
}
This is my routine dealing with await and async using a Promise with resolve and reject mechanism
// step 1 create a promise inside a function
function longwork()
{
p = new Promise(function (resolve, reject) {
result = 1111111111111 // long work here ;
if(result == "good"){
resolve(result);
}
else
{
reject("error ...etc")
}
})
return p
}
// step 2 call that function inside an async function (I call it main)and use await before it
async function main()
{
final_result = await longwork();
//..
}
//step 3 call the async function that calls the long work function
main().catch((error)=>{console.log(error);})
Hope that saves someone valuable hours
What hasn't been mentioned in this discussion are the use-case implications of the behaviour. The key thing, as I see it, is to consider what you are planning to do with the output from the top level, truly asynchronous function, and where you are planning to do that.
If you are planning to consume the output immediately, i.e. within the "async" function that is awaiting the return of the top level asynchronous function, and what you do with the output has no implication for other functions deeper in the call stack, then it does not matter that the deeper functions have moved on. But if the output is needed deeper in the call stack, then you need use "async" functions making await calls all the way down the stack to that point. Once you reach a point in the call stack where the function does not care about the asynchronous output, then you can stop using async functions.
For example, in the following code, function B uses the stuff returned from function A so is declared "async" and awaits A(). Function C() calls B(), is returned a Promise, but can move straight on before that promise is resolved because it is not interested in A()'s stuff, nor what's done with it. So C does not need to be declared as async, nor await B().
function A() {
return new Promise((resolve, reject) => {
//do something slow
resolve (astuff)
}
}
async function B() {
var bstuff = await A();
dosomethingwith(bstuff);
return;
}
function C() {
B();
dontwaitmoveon();
...
return;
}
In this next example, C() does use A()'s stuff, so needs to wait for it. C() must be declared "async" and await B(). However D() does not care about A()'s stuff, nor what's done with it, so moves on once C() returns its promise.
function A() {
return new Promise((resolve, reject) => {
//do something slow
resolve (astuff)
}
}
async function B() {
var bstuff = await A();
dosomething();
return bstuff;
}
async function C() {
var cstuff = await B();
dosomethingwith(cstuff);
...
return;
}
function D() {
C();
dontwaitmoveon();
...
return;
}
Since figuring this out, I have tried to design my code so the stuff returned by the asynchronous function is consumed as close as possible to the source.
Though your "getResult" function is async and you have rightly made an await call of myFun, look at the place where you call the getResult function, it is outside any async functions so it runs synchronously.
So since getResult called from a synchronous point of view, as soon as it is called, Javascript synchronously gets whatever result is available at the moment, which is a promise.
So returns from an async function cannot be forced to await(very important), since they are synchronously tied to the place of origin of the call.
To get what you want you can run the below,
async function getResult() {
const result = await myFun();
console.log(result);
//see no returns here
}
getResult();

Categories