The Async Await Episode I Promised
Fireship
youtubeยท 11:55standard
1.Introduction to Asynchronous JavaScript
0:00 / 0:43This chapter introduces the concept of asynchronous programming in JavaScript, highlighting its importance due to JavaScript's single-threaded nature. It outlines the topics to be covered, including the event loop, callbacks, promises, and async/await.
- JavaScript
- Asynchronous Programming
Transcript (366 segments)
0:00[Music]
0:07javascript is a single-threaded
0:08programming language yet everything we
0:10do on the web tends to be blocking or
0:12time-consuming which means that
0:14asynchronous programming is an essential
0:15skill for any JavaScript developer
0:17today's video will focus primarily on
0:19the amazing syntactic sugar provided by
0:22async await but before we can get there
0:24we really need to understand things from
0:25the ground up starting with the browser
0:27or nodejs event loop callbacks promises
0:30and then finally async await and we're
0:32going to do this without making a single
0:34joke about a sink or a wave if you're
0:36new here like and subscribe and we'll be
0:37giving away another one of a kind
0:39t-shirt with this video all you have to
0:40do is leave a comment below and we'll
0:42pick a random winner next week in order
0:44to understand anything async you really
0:46need to first understand the event loop
0:48this is ace I hope that clears up any
0:50questions you have I'm going to give you
0:53the general overview but I highly
0:54recommend you watch this talk from Jake
0:56Archibald which is the best explanation
0:58of the event loop that I've ever seen
0:59then after you're done watching that
1:01talk you should check out Stephen
1:02fluence demos with angular Channel which
1:04just released a video about callbacks
1:06which are one of the things that happen
1:07within the event loop so what is the
1:09event loop and what does it have to do
1:11with async away both the browser and
1:13nodejs are always running a single
1:15threaded event loop to run your code on
1:17the first go around it will run all of
1:19your synchronous code but it might also
1:21queue up asynchronous events to be
1:23called back later you say here's a
1:24function that I need to run but first I
1:26need to go get some data from the
1:27network the event loop says okay I'll
1:29keep doing my thing while you do your
1:31thing in a separate thread pool then at
1:33some point in the future get data will
1:35finish and let the event loop know that
1:36it's ready to be called back now this is
1:38where things get interesting if it's a
1:40macro task like a set timeout or set
1:42interval it will be executed on the next
1:45event loop but if it's a micro task like
1:47a fulfilled promise then it will be
1:49called back before the start of the next
1:50event loop let's look at the
1:52implications of this by writing some
1:53actual code first we will write a
1:55console log which is synchronous then
1:57we'll throw in a set timeout but give it
1:59a time delay of zero milliseconds then
2:01we'll have a promise that resolves right
2:03away and lastly we will add another
2:05console log for one more synchronous
2:07line of code so nothing here has any
2:10actual time delay so intuitively I would
2:12think that
2:12each line of code would be executed one
2:14by one but that's not how things work in
2:16the event loop if we execute this code
2:19you can see that first line gets logged
2:20up right away because it's running on
2:22the main thread then if we run the
2:23second line it's being queued for a
2:25future task then the promise is being
2:28cued to run in the micro task queue
2:30immediately after this current task and
2:32finally the last console log gets
2:34executed right away so even though the
2:36set timeout call back was queued up
2:38before the promise the promise still
2:40gets executed first because of the
2:41priority of the micro task queue so now
2:44that you know how the event loop works
2:45we can start looking at promises first
2:48I'll show you how a promise based API
2:49might be consumed and then we'll look at
2:51how we actually create our own promises
2:52from scratch so fetch is a browser-based
2:55API but it's also available on node via
2:57the node fetch library and it allows us
2:59to hit an HTTP endpoint and have the
3:02response returned to us as a promise of
3:04the response fetching data from a remote
3:06server is always going to be a sync so
3:08we can queue up the promise then provide
3:10it with a callback to map it to JSON the
3:13great thing about promises is that we
3:14can chain them together mapping to JSON
3:17is also a promise so we can return that
3:19promise from the original then callback
3:21and then in the next one we'll have the
3:23actual user data as a plain JavaScript
3:25object if we go ahead and run this code
3:28you'll see it runs our console log first
3:30and then it retrieves the data from the
3:31API and console logs that afterwards the
3:35great thing about promises is that you
3:36can catch all errors in the chain with a
3:38single function we can do this by adding
3:41catch to the bottom of our promise chain
3:43and it will handle errors that happen
3:45anywhere within our asynchronous code if
3:47this code were callback based we'd have
3:48to have a separate error handler for
3:50every single one of the asynchronous
3:52operations so if an error is thrown
3:54anywhere in our code it's going to
3:56bypass all of the future then callbacks
3:58and go straight to the catch callback
4:00when you start creating promises that's
4:03when you're more likely to screw things
4:04up first I'm setting up a log function
4:07so I can show you the elapsed time
4:09between each line of code up a while
4:11loop that loops a billion times
4:12arbitrarily if we run this on the main
4:15thread it's going to block all of their
4:17code from executing until the billion
4:19loops are done so we'll do one console
4:21log run our while loop and then do
4:23another console log after that and you
4:25can see it takes about seven
4:26milliseconds to finish the while loop
4:28our script is essentially frozen until
4:30that while loop is complete so let's go
4:32ahead and wrap this code in a promise so
4:34we can get it off the main thread and
4:35execute it as a micro task this is one
4:38tricky little way you might screw things
4:39up so we create a new promise we add our
4:42code inside that promise and then we
4:44have it resolved to that value when done
4:46so you might think that because we're
4:48wrapping this in a promise that we're
4:49going to execute this off the main
4:51thread but the actual creation of the
4:53promise and that big while loop is still
4:55happening on the main thread it's only
4:57the resolving of the value that happens
4:59as a micro task
5:01so the first synchronous line gets
5:02logged right away and the second one
5:04should too but there's still a 700
5:06millisecond delay because that while
5:08loop is still blocking on the main
5:09thread so to ensure that all of our
5:12synchronous code runs as fast as
5:13possible we'll refactor our code once
5:15again to say promise resolve then we'll
5:18run the while loop inside of that result
5:20promises callback by putting this code
5:22inside of a resolved promise we can be
5:24guaranteed that it will be executed
5:26after all the synchronous code in the
5:27current macro task has completed if we
5:30go ahead and run our script again you
5:32can see we get our two console logs
5:33right away and then finally the promise
5:35resolves after 700 milliseconds so now
5:38that you know all that stuff you should
5:39be in the clear to use async await
5:41responsibly we already know that
5:43promises are a huge improvement over
5:44callbacks but promises can still be
5:47really hard to read and follow
5:48especially when you have a long chain of
5:50multiple asynchronous events async await
5:53really just boils down to syntactic
5:55sugar to make your asynchronous code
5:56read like synchronous code first let's
5:59look at the async part of the equation
6:01and see what that does so here we have a
6:03regular function that does nothing and
6:05if we put the async keyword in front of
6:07it we have a function that returns a
6:09promise of nothing so whatever gets
6:12returned inside this function will be a
6:13promise of that value I'm going to reuse
6:17this get fruit function throughout the
6:18lesson just to simulate what a promise
6:20based API looks like in this case the
6:22user can pass in the name of a fruit and
6:24then the function will resolve to the
6:26value of the fruit emoji from this
6:28object and just to make this a little
6:30more clear if we didn't use the async
6:32keyword we could write this function by
6:34just returning a promise that resolves
6:37to this value so when you use the async
6:39keyword the matte
6:40that happens is that it takes the return
6:42value and automatically resolves it as a
6:44promise but that's not everything that
6:46it does it also sets up a context for
6:49you to use the await keyword the real
6:52power of an async function comes when
6:54you combine it with the away keyword to
6:55pause the execution of the function now
6:58I'm going to write a second async
7:00function called make smoothie what we
7:02need to do is get multiple fruits and
7:04then combine them together as a single
7:06value instead of chaining together a
7:08bunch of then callbacks we can just have
7:10a promise resolve to the value of a
7:12variable a weight is like saying pause
7:14the execution of this function until the
7:16get fruit promise results to a value at
7:18which point we can use it as the
7:20variable a and then we'll move on to the
7:22next line of code after we get a
7:24pineapple we can then get a strawberry
7:26and then we'll turn them together as an
7:28array one of the most annoying things
7:30with promises is that it's kind of
7:32difficult to share result values between
7:34multiple steps in the promise chain but
7:36async/await solves this problem really
7:38nicely the code on the right is what
7:41this would look like if we wrote it with
7:42just regular promises and as you can see
7:44there's a lot more code and a lot more
7:45complexity there now if you're already a
7:48JavaScript expert then I'm kind of
7:49trolling you because you know that the
7:51code on the left is making the single
7:52biggest mistake that people make when
7:54using async await and that is failing to
7:56run the code concurrently if we go back
7:59to the code on the left you can see that
8:00we're waiting for a pineapple to resolve
8:02and then we're getting a strawberry
8:04afterwards but we could get both of
8:06these things at the same time you really
8:08only need to await one thing after the
8:10other if the second value is dependent
8:12on the first value for example if you
8:13need to get a user ID before you can
8:15then retrieve some data from the
8:17database let's imagine we're making
8:19these calls from a remote API and
8:21there's about a second of latency if we
8:23run this code again with a delay you can
8:24see it takes a full second to get the
8:26first fruit and then a full second to
8:27get the second fruit but the whole point
8:29of the event loop is to avoid blocking
8:31code like this so we know that an async
8:34function always returns a promise so
8:35instead of doing one after the other we
8:38can add both of our promises to promise
8:40all this will tell all the promises in
8:42the array to run concurrently and then
8:45have the resolved values be at that
8:46index in the array so this is something
8:48that you should always be thinking about
8:50when working with async functions you
8:52don't want to accidentally pause
8:53function unnecessarily so instead of
8:56awaiting a whole bunch of individual
8:57promises you might want to add all your
8:59promises to an array and then await that
9:01promise all call and as you can see here
9:04we've doubled the speed of the original
9:06function another nice benefit of async
9:08await is error handling instead of
9:11chaining a catch callback to our promise
9:12chain we can just wrap our code in a
9:14try-catch block this offers much better
9:16flexibility when handling errors that
9:18might occur across multiple promises if
9:20we take our code from the last example
9:22and throw an error in the middle of it
9:24we can then catch that error down here
9:26in the catch block the first thing we'll
9:28probably want to do here is console.log
9:29the error and then we can either catch
9:31the error and throw another error or we
9:34can catch the error and return a value
9:35your decision here will dictate the
9:38control flow for the consumer of this
9:40promise if you return a value it's
9:42basically like ignoring the error and
9:43then providing some replacement value so
9:46the consumer the promise won't get an
9:47error but instead they'll get the result
9:49value inside of the then callback in
9:51contrast if we throw an error inside of
9:53our catch block it will break the
9:54consumers promise chain and be handled
9:56by their catch callback now I want to
9:59show you a couple of tricks to make your
10:00code as sweet as possible let's imagine
10:02we have a string of IDs and then we want
10:04to retrieve all these ideas from the
10:06database we can use a ray map to convert
10:08them to an array of promises and then
10:10resolve them all concurrently using
10:12promise doll that looks great but you
10:14need to be careful when using
10:15async/await
10:16in a map or for each loop because it
10:19won't actually pause the function in
10:21this context so normally we would expect
10:22this loop to stop if we do a wait get
10:25fruit but that's actually not what
10:26happens in this case instead it will run
10:28all these promises concurrently so that
10:30might not be the behavior that you're
10:32expecting if you want to run a loop and
10:34have every iteration in that loop a way
10:36to promise you need to use a traditional
10:38for loop so you can write async
10:40functions and then write a for loop
10:42inside that function and then use the
10:44await keyword inside the loop when you
10:47write your code like this it will pause
10:48each step of a loop until that promise
10:50is resolved but more often than not
10:52you'll probably want to run everything
10:54concurrently and a cool thing you can do
10:56is use the await keyword directly in a
10:58for loop if you have a promise that you
11:00know results to an array you can
11:02actually just use the await keyword
11:03directly in your loop so you can say for
11:05await in your code what
11:07we'll await the array of items to
11:09resolve and then loop over them
11:10immediately after and as you can
11:13probably imagine you can also use the
11:14await keyword in your conditionals on
11:17the left side of the conditional we can
11:19await the result value from a promise
11:21and then we can see if it's equal to
11:22some other value so that gives you a
11:25super concise way to write conditional
11:27expressions when working with promises
11:29hopefully that gives you some ideas on
11:31what you can do with async await in ES 7
11:33or typescript it is truly one of the
11:36sweetest things to ever happen to
11:37JavaScript if this video helped you
11:39please like and subscribe and make sure
11:41to join the live stream next week for
11:42the t-shirt giveaway and if you want to
11:44take your development to the next level
11:45consider becoming a pro member at
11:47angular firebase comm you'll get access
11:49to all kinds of advanced content
11:51designed to help you build and ship your
11:53app faster thanks for watching and I'll
11:55talk to you soon