This is my Javascript coding. I think the results are 1 2 3 4 5.
async function fn1 () {
console.log(1);
await fn2();
console.log(3);
};
async function fn2 () {
console.log(2);
};
fn1();
new Promise((resolve, reject) => {
console.log(4)
resolve()
}).then(() => {
console.log(5)
})
But. The results are: 1 2 4 5 3.
// functions declaration
async function fn1 () {
console.log(1);
await fn2(); // wait for async function fn2(which gets dispatched on thread 3) => so console.log(2) should be here chronologically
console.log(3);
};
async function fn2 () {
console.log(2);
};
// thread 1 starts (the actual execution code)
fn1(); // since fn1 is async it gets dispatched on thread 2
new Promise((resolve, reject) => {
console.log(4)
resolve() // trigger () => {console.log(5)}
}) // promise declaration
.then(() => {
console.log(5)
}) // execute the promise right away
Put it simple, console.log(1), console.log(2), console.log(3) happens on one thread chronologically, console.log(4), console.log(5) happens on the other thread chronologically. And they are intersecting each other.
Side Note: JavaScript itself is single-threaded and does not support multi-threading!(aside from web worker etc., in our context of "async") I simplified a lot and used the term thread here just to make it easy to be understood. In order not to mislead you on the concept of asynchronous operations, I recommend you to have a read on this QnA if you are not really sure on how async works in JavaScript.
The thing is that JS code are essentially async. So, before it executes the '3' printing, it already has fired the other instructions and theses ends before that ending.
The executions of fn1() and new Promise() above are executed asynchronously, that's why the order of instructions are independent. If you want to have your desired result you can try below code:
async function fn1 () {
console.log(1);
await fn2();
console.log(3);
};
async function fn2 () {
console.log(2);
};
async function makeExectionOrder(){ // move the blocks into asynch function
await fn1(); // make synchrounous call
new Promise((resolve, reject) => {
console.log(4)
resolve()
}).then(() => {
console.log(5)
})
}
makeExectionOrder()
You have to understand stack and queue:
More information: stack and queue video or ducumentation
When you do a new Promise(fnResolvingOrRejecting) the function fnResolvingOrRejecting is immediately called so it's on the same stack. Nothing is queued yet.
If you understand what stack and queue is you could explain your code better omitting the confusing async and await syntax.
The syntax would really improve code once you understand what it actually does but in this case I'll leave it out so you can see what code is executed as a callback/result handler and what code is on stack.
function fn1 () {
console.log(1);//on the same stack as calling fn1
fn2()//executing fn2
.then(//first queued
() => console.log(3)
);
};
function fn2 () {
return new Promise(
(resolve)=>{
console.log(2);//on the same stack as calling fn1
resolve();
}
);
};
fn1();//calling fn1 immediatly logs 1 and 2 because they are on the same stack
new Promise((resolve, reject) => {
//after calling fn1 and queing console.log(3) this is executed because it's on
// the same stack
console.log(4)
resolve()
}).then(() => {//second queued
console.log(5)
})
Related
I have a question about the async/await execution.
example codes
async firstMethod(){
new Promise((resolve, reject)) => {
setTimeout(() => {
resolve("test1");
}, 3000);
});
}
async secondMethod() {
new Promise((resolve, reject)) => {
setTimeout(() => {
resolve("test2");
}, 1000);
});
}
await firstMethod();
await secondMethod();
So, When the two methods are executed, the following results are obtained.
test2
test1
However, if a return is attached, the result value is as follows.
async firstMethod(){
return new Promise((resolve, reject)) => {
setTimeout(() => {
resolve("test1");
}, 3000);
});
}
async secondMethod() {
return new Promise((resolve, reject)) => {
setTimeout(() => {
resolve("test2");
}, 1000);
});
}
await firstMethod();
await secondMethod();
test1
test2
Why is that? I'd appreciate it if you could explain it.
In the first case you just await the outer promises (that are the firstMethod and secondMethod functions) and the inner promises created by new Promise do not get awaited, and simply run to completion in the background.
In the second case, because of promise unwrapping you await the returned inner promises together with the outer function promises.
The reason why in the first example those 2 functions do not run in order is because you are not waiting for anything. If you try to remove the async from the function definition in the first example you will get the same result because the function does not need the async because it does not require an await. What you could do to have the same result has the second example is by adding a await before the new Promise.
Note: You also do not need the async in the second example because you are not waiting for anything, you are just returning a Promise in which you wait outside the scope.
I'm trying to understand why this piece of code doesn't behave as I expect:
async function test() {
await setTimeout(() => {
console.log('done')
}, 1000)
console.log('it finished');
}
test();
This first prints it finished and then prints done afterwards. Shouldn't this code wait for the timeout to finish before executing console.log('it finished'); or have I misunderstood something?
You can only usefully await a promise.
setTimeout returns a timeout id (a number) that you can pass to clearTimeout to cancel it. It doesn't return a promise.
You could wrap setTimeout in a promise…
async function test() {
await new Promise( resolve => setTimeout(() => {
console.log('done');
resolve("done");
}, 1000));
console.log('it finished');
}
test();
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!
If you want to execute code after a callback is called in JavaScript, then you can just place it after the callback:
function demoCallback(callback) {
callback()
console.log("I execute second")
}
demoCallback(() => {
console.log("I execute first")
})
Is it possible to do the same thing with an ES6 Promise from within the scope of the function? Let's say I have a function that returns a Promise:
function demoPromise() {
return new Promise((resolve, reject) => {
resolve()
console.log("I execute first")
})
}
demoPromise().then(() => { console.log("I execute second") })
The Code inserted after resolve executes once the Promise is resolved, but before then is called outside the scope of the function. Is there a way that I can execute code after both, but do so from within the scope of the function?
Is it possible to do the same thing with an ES6 Promise from within the scope of the function?
No, this isn't possible. then callbacks always run asynchronously, and that includes being asynchronous in regard to the resolve() call.
(That said, promise callbacks are queued, so you can abuse that queue to get your code behind the other:
function demoPromise() {
const p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
p.then(() => {
console.log("I execute second");
}); // because I will be scheduled second
}, 1000);
});
return p;
}
demoPromise().then(() => {
console.log("I execute first");
}); // because I was scheduled first
But please don't do that)
If you want to execute code after a callback is called in JavaScript
then you probably should not just return a promise. Take a callback that does what you want before executing your code:
function demoPromise(callback) {
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000);
}).then(() => {
return callback();
}).then(res => {
console.log("I execute second");
});
}
demoPromise(() => {
console.log("I execute first");
}).then(() => {
console.log("I execute last");
});
This is known as the disposer pattern and very useful for handling resources.
You can resolve the Promise with a function that can be called in a then block. So long as that function is called within the block, you can execute code before it like so
function demoPromise() {
return new Promise((resolve, reject) => {
resolve(function(){
console.log("I execute second")
});
})
}
demoPromise().then(f => { console.log("I execute first");f();})
I'm trying to understand JavaScript async/await. How can I rewrite the below such that the output is "Hi" then "Bye" instead of "Bye" then "Hi":
JSFiddle
sayHi()
.then(sayBye);
async function sayHi() {
await setTimeout(function() {
$("#myOutput").text('hi');
}, 1000);
}
async function sayBye() {
$("#myOutput").text('bye');
}
In order to await setTimeout it needs to be wrapped into Promise. Then with async/await you can flatten your code write it without Promise then API:
(async () => { // await has to be inside async function, anonymous in this case
await sayHi()
sayBye()
})()
async function sayHi() {
return new Promise(function (resolve) {
$("#myOutput").text('hi');
setTimeout(function() {
resolve()
}, 1000)
});
}
async function sayBye() {
$("#myOutput").text('bye');
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="myOutput"></div>
setTimeout doesn't return a Promise. Create a helper function to wrap it in a Promise and then you can await it.
function delay(fn, t) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(fn());
}, t);
});
}
sayHi()
.then(sayBye);
async function sayHi() {
await delay(() => {
//$("#myOutput").text('hi');
console.log("Hi");
}, 1000);
}
async function sayBye() {
//$("#myOutput").text('bye');
console.log("Bye");
}
Use the Promise way
sayHi()
.then(sayBye);
function sayHi() {
return new Promise(resolve => {
setTimeout(()=> {
$("#myOutput").text('hi'), resolve()
}, 1000);
})
}
async function sayBye() {
$("#myOutput").text('bye');
}
or the sayHi like this:
async function sayHi() {
await new Promise(resolve => {
setTimeout(()=> {
$("#myOutput").text('hi'), resolve()
}, 1000)
})
}
Using async/await is an excellent way to build acynchronous code in a quite controllable way. Promise based async function goes into microtasks depository, which event loop executes before events and methods contained in ordinary DOM refresh/web API depository (setTimeout() for example). However some versions of Opera and Firefox browsers set priority to setTimeout() over microtasks depository. Anyway, you can control order of execution if you combine Promise based function with async/await enabled function. For example:
// create function that returns Promise
let hi = () => {
return new Promise((resolve, reject) => {
setTimeout(_ => {
resolve('Hi '); // after 1500ms function is resolved and returns 'Hi '
}, 1500);
});
}
// create ordinary function that will return 'bye'
let sayBye = () => {
return 'Bye';
}
// create third function that will be async 'enabled',
// so it can use await keyword before Promise based functions
let sayHi = async () => {
let first = await hi(); // we store 'Hi ' into 'first' variable
console.log(first);
let second = sayBye(); // this execution will await until hi() is finished
console.log(second);
}
// execute async enabled function
sayHi();
We can add try / catch block inside sayHi() function for controlling error on promise reject(), but this is out of scope of your question.
Have a nice day!
You cannot use async/await for functions that are not returning Promise
When an async function is called, it returns a Promise. When the async function returns a value, the Promise will be resolved with the returned value. When the async function throws an exception or some value, the Promise will be rejected with the thrown value.
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.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
Usually it is used to handle data that comes from server, because when you have multiple queries it can override previous one and you will handle the wrong one.
Async/await lets you handle exactly data you are awaiting for.