If you're here in 2024 (or later), here's an updated video:
Ever had to deal with JS code that just... didn't run the way you expected it t...
For further actions, you may consider blocking this person and/or reporting abuse
Loving the article and the visualizations!
There is a gotcha however,
setTimeout(..., 0)
will not immediately put the task to the macrotask queue because of browser throttling. While the result will be the same, the reason why setTimeout fires last is because it is queued up in the macro task queue "a lot" later (4ms) rather than it being a macro task.That
setTimeout
is throttled is why Node environment hassetImmediate
. For more information about browser throttling: developer.mozilla.org/en-US/docs/W...Extremely useful and intuitive.
Love the way you describe problem and provide innovative graphical solutions.
Thanks for creating wonderful visuals.
Just wondering what tools you use for creating those. 🧐
Great. I think I understand a lot more now :) I was wondering, how did you make this image? dev-to-uploads.s3.amazonaws.com/i/... I would love to have a node REPL which also shows me the "green" stuff...
Haha I just make it manually, sorry! It's a pain to find a repl that shows that..
If you wouldn't mind, what software do you use to make it? I've been trying to figure it out for a while and came up blank. Thanks love the work.
I too wish to know this 👌
I use Keynote!
GLORY TO THE CSS
Those are dope.
Hi Lydia,
Thanks for writing this up. Great article, enjoyed it and nice animations!!
IMHO, this article is missing one bit and it would be perfect if you can update for the below change.
Now that the async function myFunc is suspended as it encountered the await keyword, the engine jumps out of the async function and continues executing the code in the execution context in which the async function got called: the global execution context in this case!
After this statement, the article can mention this is where the statement
console.log('After function')
gets executed printingAfter function
to the console.Thanks.
I got a difference answer when i tried the last code:
Async/await
executing the next lines but saving in memory not showing in the output ,untilawait
got the result. And its working synchronously. it shows firstawait
result and executing line by line.You place all console.logs in async function not outside, thus after "Before Async" it sees await, resolves promise and moves the getme() function into the microtasks, since there are no other tasks in callstack, getme() moves back to callstack and executes where it stopped i.e. at await, so res gets initialized, then 'Async function' and 'After Async' are logged.
This is interesting, you use Promise.resolve function to return a Promise directly, instead of using a callback function that return that Promise.resolve function. This way, you have resolved your Promise right in line 1, not in line const res = await x.
Thanks A LOT for this post, I been waiting a long time for such a clear explanation of this topic
Thank you so much!
Just a minor suggestion - the visualization says "Timeout!", but the content says. "In timeout!"
Otherwise, it was a very nice article. I know more about the JavaScript queues!
I have a bit of a question. From what I understood,
async
functions are there to solve the problems where there are functions that took a long time to process such as API calls. However, if the call stack waits for the Promise to resolve, then encounter theawait
keyword, it means that the execution time will still be similar. Is there any part I misunderstand?Only the async functions encountering
await
will be suspended, other functions - that don't depend on the awaited result - still run.I'd just like to interject for a moment. You still need to write Promises when you actually implement these async functions. Almost all browser and Node APIs are callback-based, not even promise-based so you either need a thin wrapper library that converts them to Promises or do it yourself.
What you don't need anymore is
.then
chain because that's the whole point ofasync
syntaxGreat article, thanks !
I have a question: What would happen if we use an actual http request, e.g.
getImage().then(res => console.log('res1')).then(res => console.log('res2')))
. getImage body would go into webapi, then into (micro?macro?) queue, and back to callStack where.then
would be executed, sent to micro queue and the same process with the next.then
...?Great work, Lydia. I wish you'd use videos instead of Gifs next time, my Macbook Pro is acting out on loading so many gifs. LOL. Respect for all the work you put into this.
Yeah I know the pain, I can't change this currently as dev.to doesn't support video 😭
Those animations works perfectly.
Had it been a video, I wouldn't have read through your excellent presentation.
I'd recommend uploading to YouTube an embedding it here. I know it's less than ideal.
Finally, there are no more tasks to run in the global execution context! The event loop checks to see if there are any microtasks queued up: and there are! The async myFunc function is queued up after resolving the valued of one. myFunc gets popped back onto the call stack, and continues running where it previously left off.
If we assume function
one
will resolve eventually after getting http response. WillmyFunc
added to the micro queue when function one resolves, because if it's added immediately, the event loop will execute it when call stack is empty even if the promise don't resolve? If so there should be a different thread to handle(wait) till promise resolved which didn't cover in the animation.Wow who would have known that the event loop is really not that complicated at all, just requires a clear explanation, thank you!
I have one question, I was following everything until the last sentence! But maybe I'm just misunderstanding it:
"...The await keyword suspends the async function, whereas the Promise body would've kept on being executed if we would've used then!"
The await keyword suspends anything below it, within it's scope (the async function), until it is resolved. And if you saved that await call in a variable, you can make use of that return value. This code below the await keyword will be on the microtask queue until it is pushed to callstack and executed, like you very clearly explained. But doesn't the Promise "body" also suspend until it is resolved? The callback that you pass into the .then() will only get executed after our promise has been resolved... and similarly to how we can make use of the value we got from await() if we stored it in a variable, we can make use of the resolved value with .then(data => etc...) So don't technically both of them get suspended equally until they receive the resolved value (or rejected value)? Perhaps I'm just interpreting "Promise body" differently...
Thanks!
Yes. It's a great article but it should consider the case of awaiting an API call or similar that takes a significant time to return. The simple example using Promise.resolve is not a typical use case. A visualisation of how such api calls would be really useful (although probably time consuming to produce).
I am not a JavaScript person. Btw, I am very curious to know how did you make these visualizations? Are there any tools you used for this?
It is so good! I've the same question.
Now I understand "The await keyword suspends the async function, whereas the Promise body would've kept on being executed if we would've used then!"
If you call:
It will run the callback inside that Promise and resolved that Promise instantly before calling
then()
since Promise constructor called its callback function.Okay, now, inside an async function, when you encounters an await statement, you run the awaited command (either a function that return a Promise
const res = await thisFuncReturnAPromise()
, or that Promise directlyconst res = await promise
), after that, you put that async function inside microstack, waiting to be resumed. That means the async function has been suspended.P/s: in async function, we all know that async function will return a Promise, but we usually allude this because the return value of an async function is only valuable when that Promise call then() or being passed after await keyword in another async function.
Maybe if you share a piece of code can be more verbose man
One of the best, if not the best, explanation of promises. The explanation I wish I had and glad I got to read today. Excellent visuals too!
Ah thank you so much! 😃
Thanks for the writeup!
There is slight room for improvement though I think to just hand in the
then
handler functions, which in turn receive the correct input automatically that way:Love it! Awesome piece. I have some residual questions. It's an old article so not sure if you're still around watching and noticing comments and questions. We shall see.
The first relates to the stack. it would help to have another layer of function call to better illustrate the stack with contents, but that aside, I have often seen something like
main()
which alludes to what you've called the Global Execution Context at the bottom of the stack. For the simple reason that it's commonly written that the event loop regains control (and checks the microtask queue) when the stack is empty. I wonder if you have thoughts on that?the async/await visualisations are awesome beyond any I have seen yet! I wonder if you would continue with one more article, that covers
.then()
with this level of clarity.For all it's awesomeness I am still struggling to understand exactly how the two executor callbacks work, most especially with regard to timing, and the microtask queue. Here is my musing (current thinking) which I'm looking to confirm or correct: When the promise is instantiated it passes a two default callbacks to the executor, and runs the executor immediately (on the stack). A call to the first argument will have the Promise update it's state from "pending" to "fulfilled" and a call to the second will have it updated to "rejected". When the executor is finished (returns) it should have called one of these (or the promise will never resolve). After it has finished the instantiator returns and the promise is one of its three states. A call to
.then()
(optional) will register one or two callback handlers (for fulfilled and rejected). If the state of the promise is currently fulfilled or rejected it will immediately queues the appropriate callback onto the microtasks queue and return. If the state is pending, then the Promise itself will, as soon as its resolver or rejecter are called queue the appropriate callback then. I'm not sure if that's entirely accurate and would love to see it documented as well as you have if it is, and or what is right if it's not.When
await
is used, there is a situation I'm not clear on too. Await works a bit likeyield
I'm told, and it seems maintains the state of the running async function (on the heap one presumes) and as you write puts the async function on the microtask queue to continue at the same line (which the preserved state enables, though said state could be on the heap or on the microtask queue who knows?). In your example the functionone
resolves quickly, instantly, but if the function we are waiting on is still pending when the async function reaches the head of the microtask queue and runs once more, what then? I would guess it simply requeues itself. But it would be great to know and to have whatever happens there, so excellently illustrated as you have.I would be so thrilled if you lent you expert hand at illustrating answers to these. Many many thnaks for the awesome work you have done to date!
Thanks for a very intuitive post. I just have one question:
If my server gets swarmed by thousand of requests, each performs an async task. Will all the async tasks wait for all the requests to be put in Event Loop queue before being processed ?
can i know how did ui do this animation. there is any tool there?
I know I'm a bit late to the party but there are several gifs that simply will not load, and if you try to open them in a new tab, you get "ERROR 9413: Could not resize the image: The animation is too large. Animation resolution is 1080×608, and at this size the maximum number of animation frames allowed is 152 (total area of all frames together must be less than 100000000), but the animation is longer than this", can this be fixed?
+1
Thanks a lot for this article! After working with promises and Async code in JavaScript quite a lot recently, I had to take a few steps back and get on top of some of the basics. I stumbled across your article that I really love. Async for dummies! I certainly feel less dumb now! Thanks 😊
This is terrific. I've used the site for years, but literally signed up because of this article and hoping to find more like this. I'm an SE that is always looking for ways to visualize/map-out concepts and solutions as well. Great job Lydia!
there is an error in the image iebp0rzfnfqsrmmjplme.png ... it should be res() and rej(), not resolve() and reject().
Hey Lydia,
your little article helped me a lot to understand promises better. I didn't know that the engine jumps out of the current function with the await keyword.
I think I found a little mistake in one of your code snippets, the open curly bracket should be removed here? Right?
Thanks for your great article !
I wish I had known this before watching so many YouTube videos and reading so many articles.
Finally, I was able to obtain a clear concept visualisation of Javascript's Async Behaviour.
I'd like to point out that no video, article, or documentation could provide the same level of concept clarity as this.
If I understand correctly the setimeout callback doesn't get called after the specified timeout because their might be other microtask queue that are waiting to be called, so the timeout parameter is only there to indicate to web api when to push the callback into the macrotask queue
I am very impressed your excellent blog. your visualization effort to understand the other interested in the javascript field engineer is very helpful , so Could you please allow me to translate it into Korean?
Ver informative article. Thank you for clarifying everything. But I have doubt "The await keyword suspends the async function, whereas the Promise body would've kept on being executed if we would've used then!" Anything below await goes to the microtask queue and similarly .then callback goes to the microtask queue so how are these two different?
Awesome work, Lydia. What an effort! And very valuable stuff too. Great thanks for sharing.
Noice! Always great work Lydia.
I already read all your articles !! wonderfull and genious !! thank you for this huge effort and your articles are very helpful ! just one thing , in the callback hell example above in line 7, shouldn't you say "saveImage ( filteredImage , (res,err) => { "instead of compressedImage . thank you !
Hi Lydia
This an amazing article, also others that demonstrating by animation.
I want to ask you permission to translate your articles to Chinese to help more persons, also should have the original post link of this course.
Hi, I think I'm at the beginning but I think there is some mishap in one of the images res.cloudinary.com/practicaldev/im...
Shouldn't Promise constructor arguments names be the same as functions in try and catch blocks?
I hope it hasn't been pointed out before, but I have no time, gotta get back to reading of this gem ;)
As soon as setTimeout api is encounter, its gets pushed out from execution callstack to webapi. Now when Promise encounter, its cb function gets pushed out to microtask callback queue. In terms of setTimeout I can understand that its WEB-API pushing cb function after timeout, but in case of promise (suppose it takes 2 min to get response from API) then how that point is trigger to push promise cb to microtask? (if it is part of JavaScript engine only why not execution is stucking there?)
I've recommended this article to people for years, but now it fails to load most of the animations. Looking at the browser debugger's network tab, they're all failing to load with 403 and a response body like:
Seems like dev.to updated their CDN with more restrictive limits... is there any way you could embed them without resizing? Or manually resize them so they're all 800px wide (that's what dev.to tries to resize them to before loading, at least in my browser)?
Hi Lydia, great work ! However, there are around 8 disabled animated pictures for this article. For example, the ones at .then and .catch are disabled. I also discovered similar information can be viewed at medium website. Could you please fix the reading problem ? I also have sent you an email about a PDF edition. Hope you have received it in your inbox.
Very helpful! Thank you
Great read, love the visuals. Thanks a lot.
it helps me understand a lot about Promise and async function. Thanks
Lydia - absolutely great explanations. We hold an internal knowledge Workshop on the topic and showed your visualization. Can we share the microtask queue visualization on our homepage in the context of our house-intern workshop?
Should have used a Promise that gets added to the queue here. The sentence makes it sound like evaluation waits for any Promise to be resolved before encountering await.
Isn't async/await just syntactic sugar for Promise-chains? There may be some differences in implementation, access to labels etc., but you make it sound like they have different semantics regarding execution.
great post!
amazing!!!!
This is soooo cool! May I know what tool you using to make the visualize stuff?
I think the
[[PromiseStatus]]
should be[[PromiseState]]
, the[[PromiseValue]]
should be[[PromiseResult]]
in this article.I want to visualise this code using call stack, web API, microtask queue, macrotask queue, event loop
But I am unable to visualise it.
Can you plz help me out to visualise it means can you plz explain it to me?
Thanks
Code snippet:
function a(){
return new Promise((resolve, reject)=> {
setTimeout(()=> { console.log("a"); resolve(); },4000)
})
}function b(){
return new Promise((resolve, reject)=>{
setTimeout(() => { console.log("b"); resolve(); }, 2000) })
}function c(){
return new Promise((resolve, reject)=>{ setTimeout(()=>{
console.log("c"); resolve(); },6000)})
}function d(){
return new Promise((resolve, reject)=>{
setTimeout(() => { console.log("d"); resolve(); },10000)})
}
a()
.then(() => {return b()})
.then(() => {return c()})
.then(() => {return d()})
.then(() => {
console.log("All finished");
})
.catch((err)=>{
console.log(err);
})
console.log("Hello");
Output:
Hello
a( after 4sec of "hello" print)
b(after 2sec of "a" print)
c(after 6sec of "b" print)
d(after 10sec of "c" print)
Super cool explanation and thanks for adding that GitHub repo at the end. Stay safez...!
Hey, great post, I have learned so much, thanks for that! But there is one thing I still can't figure out, let's say we've got couple chained then() methods, once we invoke the promise constructor, the callback is being registred as a handler for resolved data, so once this happend the callback from that then() method gets to microtask queue. My question here is what happens to the next chained then() methods? is it that once the first then() callback is invoked in the call stack and returns promise, then next calback from next then() method is being queued to the microtask queue? I hope it does make sense, I still learn english :)
Hi Lydia ! Great job !!
:D
Also, I know it's a very small typo, but you seem to have one opening bracket { too many in your image: res.cloudinary.com/practicaldev/im...
and since we're talking about code, I guess it'd break ^^
Thanks for opening the path for me to using async/await !
The given description above seems to be a bit misunderstood regarding how async/await works in JavaScript.
The engine doesn't "encounter the await keyword" after the promise resolves. Rather, it encounters await as it is executing the async function, then waits for the promise to resolve before moving on with the rest of the function's code. During this waiting period, the execution context of the async function is suspended, and control returns to the event loop, allowing other operations to run.
And the promise itself isn't "popped onto the call stack" but is instead being handled by the JavaScript engine's promise handling mechanism, which is separate from the call stack.
Thanks a lot for this article. Greate work!
Hello, I really like your post, I have a question, how do you generate those gifts? What kind of tools do you use to do that? please
Probably some AI
"Yes! However, within the Event Loop, there are actually two types of queues: the (macro)task queue (or just called the task queue), and the microtask queue. The (macro)task queue is for (macro)tasks and the microtask queue is for microtasks."
Correction
*Event Loop has six phases
*
These phases are executed sequencially
*Each phase has two micro tasks *
each phase has task two micro tasks Process.nextTick and Promises
Process.nextTick is executed before Promises.
Hi! excellent article, I had one doubt though. at the end you mentioned that await keyword would suspend the async function and promise body would've kept on being executed if we would've used "then", but doesn't the then method also gets transferred to the microtask queue after the promise is resolved, so the code in the global execution context would continue first ?
I cannot even imagine how long it took to make this post! Absolutely stellar!
To say that, I am impressed is a huge understatement. Only one word can describe this magnificent article and that is AWESOME. Keep up the great work. Super Lydia!
Great article and excelent GIFs
Saving to share with all collagues
Btw: there's a typo in res.cloudinary.com/practicaldev/im...
resolve is not found
@lydiahallie
can you please provide me with this gif from the beggining to the end
res.cloudinary.com/practicaldev/im...
This is fantastic, love the whole series!
Awesome!
Thanks!
Visualisation is really cool!
When somebody asks me how this stuff works Ill send your article
Great! Very helpful!. I really appreciate the details of this article! So I'll definitely follow up with your next posts. Thanks!
This is so perfect, i love every bit of it. thanks a thousand times
I haven't read this yet but I can't wait to do so.
You did a lot of work here.
Great post Lydia , thanks alot for this ✋🏼
Hey Lydia!
I am loving the series so far, thank you for all the stunning visuals and cool explanations.
Can't wait for more of these!
Great article, Thanks ^^
Outstanding visualization
Thanks a lot!!!
Nicely explained.. really awesome..
I think it's the best explanation I've ever read. With the animations it makes things even easier. Many thanks for the excellent work Lydia. Keep it up. Many many thanks
Thanks alots Lydia for this excellent article, you make things easy to understand :)
Nice explanation Lydia :) 🤗Love this using JS 🌟
the article contains many wrong images, which are not being rendered correctly on the page
Jesus, this article is just perfect! Congratulations!
This post is the best... Very clean... Thank you @lydiahallie
Finally figured out Promise and async! Thanks!!
Nice color and good movement!
Good Article and visualisations are very helpful for understanding the concepts.
-- Thank You
Very good, thank you!
I'm very impressed your detail blog , and visualization easily to understand the technique, even if difficulty to understand , could I translate your blog into Korean ?
thank you for this writing this post!
This visualization is great help to understand JS for me !!
I needed this. Ty.
This is an amazing article, the best I've read on the subject! 😍
(And I've been struggling with asynchronous JS and reading a loooooot of things on that topic...)
KEEP UP THE EXCELLENT WORK 🙌
I like this post. It is very easy to understand.
Perfect explained, thx
Excellent post , please which software did you use to draw your post
Thanks, those are awesome visualizations and explanations! I was recently trying to explain that no code really happens in parallel In JS and this article would have helped a lot 👍
So micro task callback doesn't get pushed to web api's ?
This is fantastic! Great explanations :)
Realy nice article about promises, probablly one of betters i read !
excellent article!
Really its Great. I think I understand a lot more now :)
Thanks alot 😊
This is so good! Admittedly a little drunk and faded out toward the end but I’ll come back fresh... I promise:D
Again, thank you so much for explaining and visualizing JS concepts so it becomes so much more clear! 💛🙌🏻
Such a great article! Thank you!
The visualisation made things very clear.
Now to go back and read all the previous ones in the series!
Wow this is great explanation
This is awesome! I was wondering what you used for all the animations?
Great article, Seriously I was very confused with Promises and Async/Await concept, after reading this article I am feeling pretty comfortable and confident. Thanks for writing this article😊.
Really good
Just amazing work. Kudos to Lydia for the art of explaining Javascript concepts.
Nice
God bless you! The best explanation ever!
Great article!!!, I could finally understand this, please keep making articles like these explaining javascript, thanks a lot!!! greetings from Argentina
Thats a cool visualization.
Great article!
Great article and visualization. Read and loved every part of it. thanks!!
really very impressive work, amazing visualizations providing much ease to the learners. keep up the good work!
Top Notch !!!!
Great job!
Explanations with visualizations are the best.
Thanks for the hard work.
One minor nitpicking I couldn't hold myself - Promises existed before ES6.
The images seems to be broken for async/await explanations @lydiahallie ?
Awesome, thanks for your explanation)
awesome gif
beautiful article, thank you very much! :)
Thanks for making my life easier!
THANK YOU SO MUCH, miss Lydia.
may I ask is requestAnimationFrame(()=>console.log('rAF')) this callback function belongs to macrotask?
Nice! Thank you for this!.
What happens when the Promise have a setTimeout inside? the microtask stops until this Promise is fulfilled?
This was weel worth the read and really clarified some concepts that where hazy to me.
Thank you 😁
This is the best article I have ever read on JavaScript,
How did you create such amazing animated GIFs??
error: which logs the string "In timeout!". => which logs the string "Timeout!".
error: we can pass that value to a resizeImage function => we can pass that value to a compressImage function
Thank you very much for making such a detailed explanation of all this🤩. YOU ARE AWESOME! 🎉
Great visualisation way of explaining such complex topic . You made it very simple thanks Lydia 🙏
Thank you )
I love you and your way to explain JS
you are my hero here
Finally someone wrote it like for an idiot :D Thank you
High quality
excellent !
thank you so much
Hey Lydia, Can you create such visualisation for 'this' in JS
Can you recommend a site where we can practice some Promise and Async/Await exercises? Thanks!
Thank you! This is a very great article.
i am blessed.
That is cool!👍
wow, it's amazing visualization ! thanks for the article..
Absolutely great post!
This kind of explanation should definitively be shared
Do you mind if I translate your post?
Hi! @lydiahallie :) Could i translate those topics to my language (Im from Argentina) and post in Linkedin! I would like to tag you also there :):):):):)
Great article, thanks for the (smooth) visualization!
Thanks
how to make those beautiful visualization?
Hi Lydia!
Great article! Thank you! I've adapted it to be a codeamigo lesson (codeamigo.dev/lessons/88) so that users can interact with the code as they learn, hope it helps someone!
You aboslute legend, thank you, been trying to wrap my around this for the past few days.
Great article! Clear and concise explanation ... thank you very much Lynda
Such a useful post & so deep
Hi @lydiahallie what's Tools are you used in design of the graph(images)
great article👏👏👏
What about animation callbacks, like requestAnimationFrame? They have a different behaviour too! (See https://www.youtube.com/watch?v=cCOL7MC4Pl0&ab_channel=JSConf)
Great article, now these concepts are very clear to me.
Dear, about ur last example. What about I should give back the "one" result to a sync function caller in order do something. Is it unfacible ? I love the way you are explaining. Best regards
Hey, @lydiahallie, the original code with callbacks has a bug in it, the compressed image is used twice.
Helpful. Ty.
Thank you very much for the lovely article
I just Love this...
i got this article one night before exam!!!.....I LOVED IT
extremely useful.