How to make async become sync - javascript

I'm still trying to figure out how the async/await works.
function func1() {
console.log('a');
func2();
console.log('b');
}
async function func2() {
console.log('1');
let value = await new Promise(resolve => setTimeout(function() { resolve('async') } , 2000));
console.log(value)
console.log('2');
}
func1();
How can I achieve output as below?
a
1
async
2
b
I try to make func2 as async and await the setTimeout, but then they whole func2 become async function. So it will print out this instead:
a
1
b
async
2

You can't make async into sync
But you can get the output you need
make func1 async and use await
async function func1() {
console.log('a');
await func2();
console.log('b');
}
async function func2() {
console.log('1');
let value = await new Promise(resolve => setTimeout(function() { resolve('async') } , 2000));
console.log(value)
console.log('2');
}
func1();

Synchronous means things are happening chronologically one after the other.
Asynchronous means things are happening chronologically independent of one another.
When you execute a task synchronously, you wait for it to finish before moving on to another task(one after the other).
When you execute a task asynchronously, you can move on to another task before the prior task finishes. But it can't be exactly guranteed.
So, in your code you've call an async function inside a sync funcion. So, accoding to above explanation, you can not gurantee that after calling async function func2() rest of the func1() will execute. Because func2() is an async funcation which you can't say how much time will it take l to end up its execution process. So, You can't make async become sync.
function func1() {
console.log('a');
func2(); // call a asyncronized method inside a syncronized method
console.log('b');
}
async function func2() {
console.log('1');
let value = await new Promise(resolve => setTimeout(function() { resolve('async') } , 2000));
console.log(value)
console.log('2');
}
func1();
But you can call that async function func2() inside func1() using await keyword so at the same time func1() will need to convert into an async function in order to use await keyword. So, in this way your desired output can be generated.
// change func1() as async method
async function func1() {
console.log('a');
await func2(); // use await keyword
console.log('b');
}
async function func2() {
console.log('1');
let value = await new Promise(resolve => setTimeout(function() {resolve('async') } , 2000));
console.log(value)
console.log('2');
}
func1();
I hope that this will help you to understand the problem.

Related

Do both functions need to be Async when being called or just the parent function?

If I have two functions and the parent function (function Two) is marked as async and uses the await keyword when calling One, will the code inside function One() run async or do both functions need to be marked as async.
function One(){
// Asynchronous Code
}
async function Two(){
await One();
}
The function that uses await must be async.
The value that you await needs to be a Promise (or the await is pointless).
Functions marked as async always return Promises, but that's only a useful way to create a Promise if you are using await inside it.
As long as the function One() returns a promise, you can await its return value. So you don't necessarily need to mark One() as async.
For example:
function One() {
return new Promise(resolve => setTimeout(resolve, 500, 42))
}
async function Two(){
console.log("Calling One()...")
let ret = await One();
console.log("One() returned:", ret)
}
Two()

How to react on function that setting timeout

I have function:
function a(){ setTimeout(()=>{console.log('a')}, 0) }
This function send console.log on very end of callstack isn't it?
How can I write a function that runs after this console.log
the only way i found is send function on the of of callstack in the same way
a();
setTimeout(()=>{ console.log('after a'), 0 });
But it looks bad for me. I tried with promise, but i can react then on 'a' function not on console.log inside.
function 'a' is uneditable
you can use "callback" , a reference to another function to the a( ) function. Example:
function yourFunctionToBeRunnedAfter(){
..
..
}
function a(callback){
setTimeout(()=>{
console.log('a');
calback(); // ==> here is your function execution.
}, 0);
}
a(yourFunctionToBeRunnedAfter);
if you have parameters to pass to the callback() call, you can use apply() or call() or bind() or the spread operator (...) example:
function a(callback,...params){ // ... is the spread operator
setTimeout(()=>{
console.log('a');
callback([...params]); // ==> here is your function execution by spreading your params to the callback call.
}, 0);
}
a(yourFunctionToBeRunnedAfter, 1,2,3);
You need to use a promise. I'd recommend using async-await, but it really depends on your preference.
function a () {
return new Promise(resolve => {
setTimeout(() => {
console.log('a')
resolve()
}, 0)
})
}
a().then(() => console.log('after a'))
If you need to know when timeouts finish often, I'd recommend making a helper function:
const wait = (time) => new Promise(r => setTimeout(r, time))
Then you can use it like so:
(async () => {
console.log('Hello')
await wait(1000) // wait 1 second
console.log('Hello a second later')
})()

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

Is using async in setTimeout valid?

I had a asynchronous function in Javascript and I added setTimeout to it. The code looks like that:
let timer;
clearTimeout(timer);
timer =setTimeout(() => {
(async() => {
await this._doSomething();
})();
}, 2000);
The purpose of setTimeout is to add 2 seconds before function will be run. It is to be sure that user stopped typing.
Should I remove async/await from this function now, since setTimeout is asynchronous anyway?
setTimeout adds a delay before a function call, whereas async/await is syntactic sugar ontop of promises, a way to chain code to run after a call completes, so they're different.
setTimeout has terrible error-handling characteristics, so I recommend the following in all code:
let wait = ms => new Promise(resolve => setTimeout(resolve, ms));
and then never call setTimeout directly again.
Your code now becomes:
let foo = async () => {
await wait(2000);
await this._doSomething();
}
except foo waits for doSomething to finish. This is usually desirable, but without context it's hard to know what you want. If you meant to run doSomething in parallel with other code, I recommend:
async () => { await Promise.all([foo(), this._otherCode()]); };
to join and capture errors in the same place.
If you truly meant to fire and forget _doSomething and not wait for it, you can lose the await, but you should try/catch errors:
async () => {
let spinoff = async () => { try { await foo(); } catch (e) { console.log(e); } };
spinoff(); // no await!
}
But I don't recommend that pattern, as it's subtle and can be easy to miss.
/* contrived example alert */
var foo = 'poo';
function setFoo(callback) (
setTimeout(function(){
foo = 'bar';
callback();
}, 100);
);
setFoo(function() {
alert(foo);
});

Wait for deep async await results from deep function calls? [duplicate]

This question already has answers here:
Using async/await with a forEach loop
(33 answers)
Closed 6 years ago.
I'm using async await via babel-plugin-transform-async-to-generator.
At the top-level I'm awaiting a function response. Then there another two async functions func1 and func2. func2 asynchronously retrieves the content of https://www.google.com.
The following script returns:
go() called
func1() called
finished
func2() called
func2() called
func2() called
How can I only console.log('finished') after all call are executed successfully? Is it possible without returning them explicitly as Promises using resolve/reject?
This example is greatly simplified. What I'm trying to do involves recursive function calls I'd to await as well
const rp = require('request-promise')
go()
async function go() {
console.log("go() called")
await func1([1,2,3])
console.log("finished the script")
}
async function func1(arr) {
console.log("func1() called")
arr.forEach(async function(element) {
await func2()
})
}
async function func2() {
var res = await rp('https://www.google.com')
console.log("func2() called")
}
I'm still not sure how to do this for recursive calls but will create a separate question / example for it.
The above example can be fixed by using for..of instead of forEach. The inner functions results can't be awaited.
const rp = require('request-promise')
go()
async function go() {
console.log("go() called")
await func1([1,2,3])
console.log("finished the script")
}
async function func1(arr) {
console.log("func1() called")
for (let item of arr) {
await func2()
}
}
async function func2() {
var res = await rp('https://www.google.com')
console.log("func2() called")
}

Categories