js - How to call an async function within a Promise .then() - javascript

First, I have to mention that I already look through many questions in stackoverflow, but many doesn't answer my question. Not to mention many doesn't even have an answer.
How do I achieve the following, making sure functionB() executes after functionA() finishes?
Note: I do not want to convert my async functions to new Promise(resolve=>{...})
because I'll have to convert the someServiceThatMakesHTTPCall() as well, and any other async functions within the call stack, which is a big change.
function functionThatCannotHaveAsyncKeyword() {
functionA()
.then(async function() {
await functionB();
})
.then(function() {
console.log('last');
});
}
async function functionA() {
console.log('first');
await someServiceThatMakesHTTPCall();
}
async function functionB() {
console.log('second');
await someServiceThatMakesHTTPCall();
}

Your approach using await in an async then callback will work, but it's unnecessarily complex if all you want to do is call the async function and have its result propagate through the chain. But if you are doing other things and want the syntax benefit of async functions, that's fine. I'll come back to that in a moment.
async functions returns promises, so you just return the result of calling your function:
function functionThatCannotHaveAsyncKeyword() {
functionA()
.then(function() {
return functionB(someArgument);
})
.then(function() {
console.log('last');
}); // <=== Note: You need a `catch` here, or this function needs
// to return the promise chain to its caller so its caller can
// handle errors
}
If you want to pass functionA's resolution value into functionB, you can do it even more directly:
functionA()
.then(functionB)
// ...
When you return a promise from a then callback, the promise created by the call to then is resolved to the promise you return: it will wait for that other promise to settle, then settle the same way.
Example:
const wait = (duration, ...args) => new Promise(resolve => {
setTimeout(resolve, duration, ...args);
});
async function functionA() {
await wait(500);
return 42;
}
async function functionB() {
await wait(200);
return "answer";
}
functionB()
.then(result => {
console.log(result); // "answer"
return functionA();
})
.then(result => {
console.log(result); // 42
})
.catch(error => {
// ...handle error...
});
Coming back to your approach using an async then callback: That works too, and makes sense when you're doing more stuff:
const wait = (duration, ...args) => new Promise(resolve => {
setTimeout(resolve, duration, ...args);
});
async function functionA() {
await wait(500);
return 42;
}
async function functionB() {
await wait(200);
return "answer";
}
functionB()
.then(async (result) => {
console.log(result); // "answer"
const v = await functionA();
if (v < 60) {
console.log("Waiting 400ms...");
await wait(400);
console.log("Done waiting");
}
console.log(v); // 42
})
.catch(error => {
// ...handle error...
});

You can use promise inside the first method as
function functionThatCannotHaveAsyncKeyword() {
return new Promise(async(resolve, reject)=> {
await functionA();
await functionB();
console.log('last');
resolve();
});
}
async function functionA() {
console.log('first');
await someServiceThatMakesHTTPCall();
}
async function functionB() {
console.log('second');
await someServiceThatMakesHTTPCall();
}

if someServiceThatMakesHTTPCall is async you can avoid all that by doing the following:
function functionThatCannotHaveAsyncKeyword() {
functionA()
.then(function() {
return functionB()
})
.then(function() {
console.log('last');
});
}
function functionA() {
console.log('first');
return someServiceThatMakesHTTPCall();
}
function functionB() {
console.log('second');
return someServiceThatMakesHTTPCall();
}

Related

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

Calling a method that has an await inside, does not wait for the promise to resolve

Consider a scenario such as this :
function method1(): Promise<string> {
return new Promise((resolve, reject) => {
// do something
const response = true;
setTimeout(() => {
if (response) {
resolve("success");
} else {
reject("error");
}
}, 5000);
});
}
async function method2(): Promise<string> {
const result = await method1();
// do some other processing and return a different result
const result2 = result + "1";
return result2;
}
function method3(): void {
console.log("test 1");
const result = method2();
console.log("test 2");
}
method3();
I am not sure why method2() would not wait for the result as it contains an await. If I use await for method2() call in method3(), it works :
async function method3(): Promise<string> {
console.log("test 1");
const result = await method2();
console.log("test 2");
}
I can't really wrap my head around how the await/async work even after reading so many blog posts, Mozilla documentation and stackoverflow answers.
One of the comments said "you can't escape asynchrony". And further explained that as any async function would be returning a promise, have to await them all up the function ladder.
Hope someone can clarify this for me. Thank you.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
every async function return a promise and that will go "up the chain" up to the first call.
there are some libs that aim to make synchronous calls from promises if you really want.
but the thing is: that's just how javascript works
Mark async functions as async
Functions that await async functions are themselves async
Await async functions when you call them (if you need the result to continue execution), except at the top level, where you can use the equivalent then syntax
async function method1() {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(1), 5000);
});
}
async function method2() {
console.log("starting method 2");
const result = await method1();
console.log("finished method 2");
return result + 1
}
async function method3() {
console.log("starting method 3");
const result = await method2();
console.log("finished method 3");
return result + 1
}
method3().then(result => console.log(result))

Why await is not waiting

How to wait for setTimeout to complete first
function a() {
setTimeout(() => {
console.log('should wait');
}, 5000);
}
async function b(c) {
console.log('hello');
await c();
}
b(a);
console.log('out');
My expected output is
Hello
should wait
out
setTimeout does not return a Promise and await only works with Promises.
Also, put the console.log("out") inside the b function for it to run after the a function.
Check the code snippet below, it does what you were looking for.
function a() {
return new Promise((res, rej) => {
setTimeout(() => {
console.log('should wait');
res();
}, 5000);
})
}
async function b(c) {
console.log('hello');
await c();
console.log('out');
}
b(a);
A function must return a promise if you want example to work properly (await keywords "awaits" for returned promise to resolve): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
You example should look like:
function a() {
return new Promise(resolve => {
setTimeout(resolve, 5000);
});
}
async function b(c) {
console.log('hello');
await c();
console.log('should wait');
}
await b(a);
console.log('out');
Note that you can use await keyword on function, because declaring function as async automatically makes it return a promise.

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!

Understanding Promise and Await

I am just trying to understand how Promises and Async-Await work.
I want this to resolve by logging 1, 2, 3 in that order. Currently it logs 1, 3, 2.
I know the Promise doesn't really make sense here but in my program it has other uses so that needs to stay. The route from Caller function to Test also needs to stay (If need be you can change these but just know that they are there for a reason)
My question is how do I wait for the Caller function to resolve?
Here is my code:
function Test() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('2');
resolve();
}, 2000);
})
}
function Caller() {
Test();
}
console.log('1');
Caller();
console.log('3');
I have tried what I understand, which is to make the Caller() function await the Test Promise, but that of course makes the Caller() function async and therefore we still get 1, 3, 2
async function Caller() {
await Test();
}
Is there maybe some way to use await without making the function async?
You can only await a function that returns a promise (well, not quite true, if it doesn't return a promise it creates a promise that resolves instantly)
You can only await when you are inside an asynchronous function
function test() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('2');
resolve();
}, 2000);
})
}
async function caller() {
console.log('1');
await test();
console.log('3 (this is blocked awaiting the promise');
}
caller()
console.log("This is not blocked because caller is async");
This is a very straightforward, simple way of doing what you ask.
The await keyword can only be used inside functions
defined with async.
function test(ms) {
return new Promise((resolve, reject) => setTimeout(resolve, ms))
}
async function caller() {
console.log(1, ' - caller() started');
await test(2000).then(() => {
console.log(2, ' - test() resolved')
});
console.log(3, ' - delayed until "test()" has resolved');
return 4;
}
// wait for "caller()" to resolve
caller().then((result) => {
console.log(result, " - caller() finished")
});
console.log(5);
Here's a good article by Google which expands on the subject:
Async functions - making promises friendly.
Cite source.
here is how you could use functions like this:
function sleep(ms) {
return new Promise(r => {
setTimeout(() => r(), ms);
});
}
(async () => {
console.log(1);
await sleep(1000); // 1s
console.log(2);
await sleep(2000) // 2s
console.log(3)
})();
The previous answers are all correct but I just feel like this answer makes more sense. It is more accurate to the original question's code:
function Test() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('2');
resolve();
}, 2000);
})
}
function Caller() {
return Test();
}
(async() => {
console.log('1');
await Caller();
console.log('3');
})();

Categories