Async Javascript Tutorial For Beginners (Callbacks, Promises, Async Await).

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
Who am I kidding I don't even go outside hello there my gorgeous friends are the intern that I'm happy to announce you that I'm getting very close to the completion know it sounds weird to the completion of the course of the JavaScript course so what I talked I'm gonna do is share a small part of it here on YouTube for you to enjoy and see if you like it we're gonna talk about asynchronous JavaScript it's a harder topic to kind of understand but I'll try to simplify it as much as possible so again this is a small chapter to kind of get you up and running with it and then in the course we're gonna start building up projects and all of those good stuff yeah I have like 20 hours filmed it's gonna be amazing next week I'm gonna start sharing like everything that I have in the course see if you like it than everything and yeah that's gonna be it so enjoying this part and I'll see you in the next one okay in this chapter we are going to talk about asynchronous JavaScript and how that is useful for us so a big thing that you're gonna see on the Internet is something called Ajax so what is ajax ajax means asynchronous JavaScript and XML what is XML we don't care because nobody uses XML anymore but XML is basically a format a lightweight easy way web format that people use to kind of send data from server to the browser or from server to another server and things of that sort okay but again we're not going to be using XML we're gonna be using something called JSON alright which is again just another format of sending data a common way because you're gonna see that we have to send data from like a server to our browser and the thing is that a lot of programming languages can use that like they can get some data and it has to have some kind of common syntax all right again let's not worry about that right now we're gonna get into that in just a bit let's just worry about asynchronous JavaScript what is asynchronous JavaScript and why do we use it so so far everything we've been writing mostly was synchronous so how is asynchronous useful well take a look normal behavior of a website is let me let me see something here let's just pull up a page or something I don't know like let's click here on dribble it's good to dribble okay once the zoomed out okay there we go so the normal behavior is like you go here you click on something and when you click on something that data gets back from a server and the HTML CSS and JavaScript automatically updates right so if I click here it's gonna fetch that page it's gonna fetch all the information on that page and it's gonna bring it back and it's gonna update everything for us Ajax allows us to kind of make these requests to get data from a server in the background and what you get is this kind of live update view so for example if I search on YouTube here I search tool as you can see everything is live updating here all right and this is some data that's getting back from like some Google servers so as soon as I start writing as you can see this automatically updates without actually clicking on something or like having to refresh the page to get the whole data back all right so it's basically a dynamic data that's coming back for us all right and this is super useful I can even show you here on can I use so again this is kind of a website that shows you basically compatibility of the browser's of like different features so if I search flexbox as you can see as soon as I start typing everything automatically updates here or the HTML the CSS C so again what's happening in the background basically it's using Ajax it's sending some kind of request to a server and that server gets back the information and the format alright so again we get that information back in a format called JSON alright and we take that JSON format that contains all the data we turn that we parse it into JavaScript useable code and then we just update the information on the screen just like this okay so that's kind of the goal behind it now let's take a look on how asynchronous code actually looks okay so let's quickly just recap on how synchronous code looks in JavaScript all right and I'm gonna show you how a synchronous code looks so let's do a sink sink code example all right so let's just do simple super simple console logs so this is the start here console log and all right and remember if we add a function and we invoke it let's just do a function here other functionality like that I'm gonna just gonna do console log we are in another function console log do some stuff alright and that's it so what happens if I call it let's call it here right in the middle okay so again synchronous code again JavaScript is gonna read your code line by line all right javascript is pretty bad at reading code so it can only do it one line at a time so it goes from here to here alright it checks this function it adds it to the memory then it counts a lot starts and when we invoke a function if you remember we basically create a new execution context so when we invoke a function we go inside the function so we start reading this function we start reading not this function this console.log and this thing and finally when we're done with the function it closes right it gets popped off of that call stack that we talked about and again the call stack is kind of a way for JavaScript to keep track of all your execution context basically when this code starts running at the beginning right your file actually starts getting read this calls back this main gets added this main execution context gets added which is gonna start reading your whole file here all right so it starts here alright it's just a memory it adds console.log on top of the all stack here this is gonna do something like console.log right let me make the smaller hundred alright then this one finishes so after this finishes running this function and gets popped up alright so it gets deleted down and then we invoke other function so now what we do is we add other function on top of the call stack alright just like that now our main is not going to continue running all right so we're not continuing down here and the console.log end we jump into this other function execution context all it means is that we're gonna go here we're gonna console.log this out console lock this out and now the function is done alright so it gets popped off of this stack so it gets removed and finally we console.log out end alright so this gets added now here so let's do just a console.log all right this gets added now here and after this is done then everything gets removed and we are done ok and we can see this in action I'm just gonna run it here in node node AB KS alright so we have start and then we do the other stuff all right so everything that we have in a function because we invoked it and then we run end ok so super normal behavior now let's take a look on how asynchronous code runs I'm gonna remove everything actually let's just remove this and this I'm gonna rename this to async all right now there are specific async async' things that we can do here so one of those are set timeout all right so this is a specific thing that is gonna do a sync operations so I'm gonna add set timeout here which takes a callback function just like that I'm gonna add a delay of 2,000 seconds all right so now every code that we write in here it's gonna be asynchronous so I'm gonna console.log we are in the timeout again all this thing does is it's gonna delay the code in here by 2 seconds all right if I hit save and I run this code how do you think it's gonna run we get start we wait 2 seconds and then we get end so hopefully that's clear so we can't lock the start then we wait 2 seconds we get we are in the timeout and then we get end well let's take a look and no that's not what's happening take a look we have start and and then we are in a timeout so let's run this again I'm gonna add 5 seconds now run start end and take a look now we got we are in a timeout so it didn't actually block the code here right it didn't stop at this moment and then run down here but if we learned about like how the call stack works this doesn't really make any sense because we learned that okay well let's go back at this example so our main script tag here starts running we add the console.log first so we have start running ryan counts log again let's make this smaller and that's too small no not that small and we have the console log this finish is running so it gets removed and then we run the set a set timeout function set timeout alright so that starts running but then again we cannot run console.log here right we have to wait for this one to finish before we can run the other one so what's going on here why is this running right after and then this kind of just pops in randomly so what's happening is again javascript is very bad at kind of doing multitasking all right I can only do one thing at a time it's a single-threaded programming language so it can only reads code line by line but there's actually something else going on we have the browser because we're running JavaScript in the browser so there are these things called web api's that can handle those things separately for us so when we call the set timeout javascript is basically gonna pass this timeout inside this web api s-- and the browser is basically gonna keep track of of the time here all right so we kind of pop this set timeout off the call stack so we remove it and we pass it here this is gonna keep a timer and then we continue running our code all right so it doesn't block the code we continue running everything and these asynchronous codes get passed to the web api s so now here console.log gets ran the other the finished one right console.log the last one down here and once this is done this gets popped off all right so this gets removed and at the end when the set timeout you know like five seconds pass it gets pushed back on to the call stack and it runs it runs our callback right here alright so hope that clarifies things so we even saw like when we have a click listener write add event listener on click well shouldn't this kind of like block the code why can we like read the rest of the code should then we wait for the user to click on something well again things like this like click listener that also is passed here and the web api is and keeps track on when the user clicks and when the user clicks then our callback function gets executed and it's going to be passed on to the call stack so it gets invoked okay so that's kind of behind the scenes and there are a few things here that are asynchronous such a set timeout we're gonna take a look at fetching data or fetch I should say that's what it's called and that is also asynchronous at timeout set interval and things of that sort now you're gonna see that they have this pattern of having a callback function right so set timeout for set interval they all use they call that function because after that certain period of time or when we get or even when we've had some data from the internet once that data is available then we want to kind of manipulate it or run it and they call that function and we're gonna take a look at this in the next episode but I just want to quickly mention that callbacks are not necessarily always asynchronous so for example if we have an array here Const and let's just do items is equal to let's just do 1 2 3 4 5 right if I do a items dot for each well for each here takes a callback function as well like that all right let's call back and here and I have access to all the item each individual item so I can cause a log item all right so take a look here and this callback this is gonna be ran before we adhere to the end all right it's not gonna be a synchronous so if we run this start 1 2 3 4 5 and then end all right so it's gonna loop over this until it finishes before we get down here okay so I just want to mention that you're gonna have callback functions that can they're not necessarily all of them are asynchronous they can be synchronous too okay so let's get into an example on how we can create or like kinda like simulate asynchronous code okay and this one let's try to give like and simulate an example on how it would be for you to get some data back from a server okay so let me kind of show you a problem that we might have if you try to write code synchronously so if I do something like start alright this is kind of just so we can see what's going on where the start and the finish is just like that and in here I'm just gonna create a function a let's see we're trying to login a user so I'm gonna say login user alright and let's say this takes an email and a password okay and let's see when we login the user we want to get back the email so what I'm gonna do is just set the timeout again this is kind of we're simulating like this is gonna take some time to come back alright so that we're just gonna pass in an arrow function in here come Hahn mr. arrow function there we go alright so in here what we would do is let's say we just want to return the email so I'm gonna just return I'm gonna create an object here just user email it's gonna be set to the email that we're gonna receive all right so let's say we're trying to login the user and it's let's just say it's take it takes a thousand five hundred milliseconds again we don't know like how much is it gonna take when we're actually working with a real server or with an API well let's just say this one takes 1,500 seconds okay so we cannot do something like that like we cannot get this information like this cost user is equal to log in user I'm gonna pass in the email and the password so let's do David at GU mail.com it's a real tank I promise and my password is one two three four five six alright so what's happening here we're invoking the function and I want to return the email all right we're passing that this email so I want to have this here right we're returning it the thing is that this comebacks after some time in this case a thousand five hundred so if I try to console.log user down here we're gonna see that it's not gonna work yeah where's the browser I'll just do it here if I run this node app start undefined and finished so user gave us undefined why again the information did not come back yet when we cancel log the user down here alright this took too much time so if I do something like 5,000 here all right we get start finish undefined 1 2 3 4 5 and this is when the actual information gets back and to see that I can even add a console log and this set timeout so I can say now we have the data but when I try to access it down here I did not have it so run start on the fine finish let's wait a bit and now we have the data alright so how can we get around this issue alright we cannot run synchronous style code here because we don't have the data so what we can do is we can pass in a callback alright callback functions are super important again a callback function is just a function that's passed in as a parameter that's gonna run later on in a later time so what we do is we pass in a callback function here alright this is gonna be a function so now I can add a comma here and invoke that function right so I can pass in a curly brackets and parentheses alright so this is the function that I'm invoking here so now what I say rather than returning here what I'm gonna do is I'm gonna wrap this thing and a callback alright so now I'm passing this user email as a parameter and this function here that I'm calling back so here I will have access to that user alright then I can do user dot user email so here I can say console log user dot just let's just do user ok so recap we just pass in a callback function here alright which is here and once the data come backs so when the set timeout here runs we invoke that callback function which triggers all of the functionality and here so in here is where we actually have access to the user so let's take a look let's run this note app start-finish and look at that after five seconds boom we have the data and I get the correct data and here user email devil at GU mail blah blah alright so there we go that's kind of the idea behind it we passed these callback functions now you might also want to do something else like once you get back the user you might also want to get these videos so let's create another function let's see how that looks function get user videos all right and here let's see it takes an email parameter so we take a look at the email and let's just fake a time out here as well let's see getting the videos takes that's quite fast it just takes a thousand second a thousand milliseconds okay so here again if I do return let's do video one just a simple array video to video tree okay so we return something again if I want to run this after I get the user information back what I would do is again addy call back to this so get go to the get user videos add a comma call back just like that alright what do you do is you pray replace the return here with the call back so when you invoke this function after I get back the user details so here's where I get back the user detail after I get back the user detail I can get that users videos and I can pass an user dot let's see here what we have user email right user dot user email and the second parameter if we take a look here again take a look it's the call back so I'm gonna add another call back here like that and here we have access to the actual videos videos like that console.log videos all right let's see how this looks run oops messed it up oh my goodness why you do this run this start finish alright we get this back after five seconds the user and as soon as we got back the user we started getting the video back so let's just add two seconds here and three seconds here let's make this shorter okay one two three we get the user back as soon as we get the user back is trying to fetch the videos which takes two seconds now the problem is that when you try to fetch things like multiple times so I want to fetch the user that has videos and then maybe like video details I can add another one here function video details alright this one takes in the video and a callback this is gonna kind of duplicate the functionality here alright so when you keep stacking these things let's say this just gives us back the title of the video title of the video or something right so here what we can do is do another one video deed after I get back beat all the videos I want to get back let's say video zero and then we pass again another callback here so here we have access to this and here so the title or the description also long title so as you can see you get in this weird nested structure of callbacks and callbacks and callbacks and invoking functions that have a callback invoking functions in the callback and they have this weird structure now imagine like you're trying to get more and more data so you're invoking more of these and you get into this weird look at this like in this weird a structure I kind of like a pyramids pyramid here or triangle and this is something that is referred to as callback hell alright that's when you keep stacking these things one on top of each other and it's very hard to read and you don't know it's hard to read and you don't know what's going on alright so in the next chapters we're gonna take a look on how we can fix this and make this easier using promises and we're also going to take a look at eight oh wait all right so this is kind of a general idea of how asynchronous code works again don't worry we're gonna get into more detail in the next episode and yeah hope you enjoyed this one one thing that we haven't factored in in this code is when we you request some data from like a database or just an API is that we might not necessarily always get back the correct data we might get an error or something so here in our case is when we're trying to login the user we're just trying to send the data back but what happens if it fails or something so what we would do here with the callbacks is we would add something like an odd success all right and we would pass this in here as the callback so on success we want to run this otherwise we would have also non failure function here all right and basically we would do something like if we have a failure or something I found a year or something wrong happens here then we would have to also run some kind of code alright so this becomes extremely extremely complex and successful so what that means is down here besides running this arrow function we would have to run another callback function to kind of handle the error - all right so this becomes super super complicated here so let's take a look at promises which kind of simplifies everything for us let me just add back callback here for a simple example okay so let's refactor this using promises actually let's just do a simple example here and then we're going to refactor this whole thing using promises so what is a promise a promise is just an object that basically gives us back either a result of an asynchronous operation or a failure of a asynchronous operation kind of like this kind of like more we did here very very similar so what we're gonna do is let's just create a promise right now all right I'm just gonna call this promise all right instead is equal to a new promise all right this is going to be an object here because kind of a constructor function and this takes in two parameters kind of like what I shows you right now a kind of base on success and all failure so if if we get the data back successfully then do something with it if we don't get it back successfully then I don't know display an error message or do something with it so the two key words here that I promise you is is is resolved so that's kind of if like it's successful and reject if we have a problem all right so we run a arrow function here and now again I'm gonna kind of simulate I'm gonna add a set timeout here to kinda simulate getting some data back from an API or something let's do two seconds so here what you would do is if you successfully got the data back you would run resolve so I'm gonna resolve I'm just gonna pass in like let's say we get back a user head here okay and that's it so this is how we created the promise but there's another step here kind of like here right we have to kind of consume it we have to execute the code when we try to get back the information so this is the creation of a promise and now we can assume the promise so what we do is we can just call promise and we're not doing any crazy stuff here like like this all right what we just do is we use promise and we add II thought then and end this dot then we have the information so the result here is I have the result or the user or whatever I just gonna run an arrow function and I can console.log user and hit save now let's take a look does that work run this oops that's also a tea console.log here comes the long gut the user hit save let's run this I keep messing it up here we go start finish and after two seconds all right we got an error let's take a look on success oh I'm trying to run that file let's try to run node promise dodge is okay and there we go after two seconds we got back the actual user so as you can see these syntax is much much cleaner and easier to read now we can also let's say we get an error back from the let's say we get an error back from the API or something what we can do is let just had a a reject here all right so let's say this doesn't resolve and it gets rejected so I'm gonna say reject and I'm gonna pass in an error here now a good practice to do that is to add a new error alright this is an error object it doesn't really have to do anything with the promise because we can create this in JavaScript I'm just gonna pass in here a new error okay and this is gonna have like a random message let's just say we're gonna display something on the screen like user not logged in okay and safe so now how can we handle that so dot dan here gives us back the result but we can also chain here so after the dot then I can add another dot and we can say dot catch and here we have access to the actual error so I can do console log error alright so we just chained things together like that so this we run this if we get the information back successfully and we run this if we don't so now if we run this again this should give us an error right now and there we go user not logged in all right so we get an error and if I want X access only the message here you can just do error dot message here let's run this again there we go user or not logged in all right so it's a super nice and clean syntax of running this but in our case here we kind of chained together multiple things like get the user login the user and after you login the user and get his videos and have free we get the videos get the video details so we're gonna refactor this whole code to use this promise syntax okay so let's do that in the next one okay let's go back to this original example and see how we can refactor this code because it looks nasty so refactor this whole thing and make it look nice with promises so let's comment everything out here like that so what will you do is rather than doing this callback thing here just get rid of it alright keep down here as well just get rid of all these ugly callbacks nobody likes them okay now what we do is we return a promise so let's return here a new promise like that again if you remember we have access to resolve and reject so let's run this and now we just pass this whole timeout in here okay and again remember if you get the data back you would just pass and resolve so we would pass and resolve here and that's it that's the whole thing and that one here as well we can do the same thing so here let's just say return a new promise all right we can pass and resolve and reject and we can run an arrow function just pass everything here if we get the result back then we resolve it same here let's do return a new promise all right we passed and resolve reject if we get the data back again we don't use callback anymore we just resolve it and that's it so let's take a look on this ugly because this is super ugly here how can we make this nicer so look at that this is super simple we have login user right so login user again if it returns us a promise and you're going to find this a lot of times like when you request data from an API you don't even have to write these up here because a request is going to return you a promise automatically but here we just manually wrote it so how can we write this code out well take a look login user alright the stakes in an email and the password boomba has the password and the if it returns a promise and you're gonna find that in a lot of cases when you make requests to an API or something you don't even have to write out the promises like this right it just comes back it's gonna return a promise automatically C or nothing I have you don't even have to write this out so again here we're consuming it so all we do since this returns they promised is we just add it dot dents I'm gonna just hit enter and go down to a new line and here we have access to the user alright user here and I have access to it I can console log out the user and so on it's gonna work just fine but what if I want to do kind of what we did here when as soon as I get as I got the user I also want to get the video details so I just get user videos here user videos like that and I can pass in the user email from here and again this returns me a promise so I can just add another dot then I get the videos I can do something video with the videos I can get back the video details if I want I can pass in video 0 for example the first one video 0 and dot then I have access to all the details console.log detail and just console.log that out at the end detail like that ok so this is the same thing as this but take a look how easier this is to read comparative to this one let's run this now Abe dodge a yes start finish alright this is gonna take a bit of time we have the data and we're gonna get back the title in just a bit there we go title of the video down here okay so again way nicer way simpler than this whole stack of code and there is actually a much easier way of writing this whole thing out because wouldn't it be nice still the best example of this would be to kind of write everything out synchronously something like that this something that we're used to doing like well if I can just do something like user is equal to login user and then pass an IDI and boomba or whatever blah blah blah right wouldn't it be nice to just write the code like this somehow and then I have access to the videos that's equal to like video details and just pass in the user from here right user email or something like that like this is the nicest way kind of like synchronous synchronous style of writing code rather than this even though this is nice this is terrible I don't like this but wouldn't it be nice to do it this way and there is a way something called async await it's kind of like a syntactical sugar and if you don't know what that means it's kind of like it still uses promises but it's just a nicer and easier way for us to write asynchronous code alright so the people over in JavaScript were like hey let's make this even nicer and easier to read so we're gonna take a look on how we can add async await to kind of simplify and make this code nicer so again it doesn't really change anything in the background it's still gonna use promises but it's just an easy and simple syntax for us to write it ok so let's do that in the next one so just very quickly I want to show you something else what we're doing here is we are getting make the user information and we're waiting for the user information once we get that back then we're doing something with it with the videos and then we're doing something with the detail there's also a way like what if I want to get some data from youtubers from Facebook but I want to kind of run them at the same time I don't want to have to wait for one specific thing to start executing the other thing right because here we have to wait like let's say this takes two seconds I have to wait for this one to kind of get back for me to start finding the videos right so what if I want to start getting data from YouTube and Facebook at the same time so what we can do let me just go back here I'm gonna comment this out very quickly so you can imagine like we have something from YouTube I'm just gonna do cost YouTube you promised let's say this is gonna return me a resolved all right it's that timeout all right then I'm gonna pass in here and then it comes to log getting stuff from YouTube and then I resolve and let's say we get back you know let's just say we got back some videos here one two three four or five videos okay okay and this is gonna take us two seconds all right now let's do the same thing kind of copy paste this here to the youth to Facebook let's say we want to get back some info from there kind of the same thing from getting stuff stuff from Facebook all right and here let's just say we get back kind of like a user or something but it's a name or something okay super simple so if I want to run these at the same time and I sort of I want to get back both like both information what we can do is we can use promise dot all all right and here we pass in an array like that and we just pass in YouTube and Facebook like that and then we have thought ten result I like to drop this in a new line by the way when I do dot them result we can run an arrow function and console.log it out all right so now what's happening is this starts getting the beta as soon as this starts getting the data as well okay so the ball kind of starts running almost at the same time and we don't have to wait for this one to get the data and then start fetching for this one they kind of both execute at the same time so when we run this we can just get back the data as fast as possible just like that look at that we have the user and we also have the videos from up here okay now one thing to note is if one of them take a longer so this takes like 3,000 it's the result is not going to come back until both of these promises are fulfilled both of them return us both of them resolved basically so take a look if we wait one two this should come back already but it doesn't getting stuff from YouTube it has to wait for this one so let me add the delay a bit bigger 5,000 here so we can do again getting stuff from YouTube's as you can see it doesn't give us the data back until we also get back Facebook okay so there we go this is promised at all it's meant so you can start executing more asynchronous code at the same time or almost at the same time and yeah it can be useful in certain cases I thought I'd show you this one as well okay let's take a look at async away this is gonna be the last one this last theoretical section on the page here because after that we're gonna actually start building out some examples and stuff like that okay so what we're gonna do here is let's get rid of this whole thing and just go back here alright to kind of refactor this whole thing to make it look like synchronous code like code that we like to look at so what I'm gonna do is just create the function here and I want to like call everything in here all right function let's say display user all right I'm gonna call a display user down here all right and take a look we're just kind of write like async style code what we're gonna do is say Const log the user alright so kind of like this here or login user I should say login user is equal to and we're gonna just call login user like that I can pass in the email and the password blah blah blah okay now since this is now gonna work as you know using a async away what you can do is just go here at the beginning and you see a wait and that's it alright now what you can do is just go ahead and here to a new line and you can use this login user it's gonna have D theta all right so what you can do is just say cons is equal to a wait get user videos and I can pass in the login user dot user email France so from here again if I want to get the video details now I can just use the videos here so Collins detail is equal to a wait video details alright and I can pass in video 0 okay and that's it that's how it works it's super simple I can console.log out the detail if I one down here okay there's one last thing though that we need to do is we need to explicitly tell JavaScript that this is going to be asynchronous code it's gonna be running here so besides this await we need to go here to the function at the beginning of it and just say async alright this is an asynchronous function that's gonna run some asynchronous code in here but that's it that's generally it's you just add a sink before the function and you add the weight and you are done let's take a look this this work run all right that's gonna give us an error what's going on then cannot access login user so let's see all right let's comment this out login user okay let's see what's up run this again yeah okay cannot access before all right so what's the error here and okay I have the same name here I'm stupid let's call this logged user and pass in here logged user there we go alright let's run this again there we go so now it works so start or it's gonna get the data and it's gonna just give us back the title so you're gonna see that it works the same way but we use kind of the synchronous style of writing code that we like and we're used to compared to like this arrow callback function nightmare or even this dot then syntax okay so it's a very nice and simple way of writing asynchronous code that we're gonna be using okay so that's kind of the general idea now how can we do the error handling like the dot catch and all that stuff like how can I make sure like what happens if I have an error here alright what you can do is you can wrap this in a try-catch so try to run this code like that and if you if it doesn't work and then catch the error and then here we can do something like display the error to the user or do something like that we could not get the videos all right something like that or we can just cancel out the error that we have here all right so you would just wrap it in a try and catch in case the code in here fails and you cannot get the logged in user or you cannot get the videos or whatever okay so those are the basics of of callbacks of promises async awaits and all of this get stuffed okay in the next parts again we're gonna stop being theoretical and actually start doing some practical things because this can be hella boring and we want to do actual things right we just don't want to learn theory we actually want to build out fun stuff all right so therefore we're gonna do in the next section
Info
Channel: Dev Ed
Views: 344,832
Rating: 4.9374623 out of 5
Keywords: javascript, javascript for beginners, javascript tutorial, async javascript, callbacks, promises, async await, javascript callbacks, dev ed, developedbyed
Id: _8gHHBlbziw
Channel Id: undefined
Length: 42min 9sec (2529 seconds)
Published: Sat Mar 28 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.