Asynchronous and Synchronous JavaScript. There and back again.
(upbeat music) - Hi, my name is Maciej Treder.
This is my handle.
You can follow me on all of those social networks, which logo types you can see right now.
I'm from Krakow in Poland.
On my daily basis, I am working for Akamai Technologies. That's a company based in Cambridge, Massachusetts, and we are making internet fast, reliable, and secure. In other words, we are a content delivery network company. Today, I would like to speak about the asynchronous and synchronous JavaScript.
The presentation is available for you offline. You can find it on my Speaker Deck together with all the URLs, which I'm going to share with you today.
It's also embedded in the QR code, which you can see right now, so you could scan it with your smartphone.
Let's go to the point.
JavaScript is a single threaded language.
What does it mean? It can handle just one particular action at the given moment in time.
So how JavaScript deals with situations like listening for DOM Events, querying REST APIs and waiting for a response without blocking the execution, listening for WebSockets or push notifications. It's done using the event loop and callbacks queue mechanism, which we are going to cover right now.
Let's examine the simple snippet which shows the synchronous JavaScript code. What we have here are two functions.
One is invoking the other one and inside the main JavaScript function, we are invoking the greet.
So the output from this code is probably as you expect, "Hello John, nice to meet you." But how the JavaScript will behave, if we will change the greet function slightly and introduce the setTimeout mechanism.
The setTimeout is a technique of delaying the output of the function or delaying the invocation of the function first as a first parameter, and as the second parameter we are describing what should be the timeout in milliseconds. So in our case, we ask setTimeout to print the "Hello John," with the zero milliseconds delay, but the output would be reversed.
What will we print first, is "Nice to meet you," and then "Hello John." The reason is that setTimeout together with setInterval and fetch and DOM, Window and much more have one common point.
Those are not part of JavaScript.
Those are external APIs, which communicate with JavaScript using the callback queue. We can examine the previous snippets step by step. So we need to introduce the stack where the synchronous code is put where for execution and the callback queue used for communication with JavaScript and the external APIs.
So first we start from the main function, then it calls greet at the very end, inside greet we first call setTimeout.
So this is where we are introducing the external API. We are asking setTimeout API to execute the console log or to put the console log into the callback queue after specified amount of time.
In our case it's zero, so setTimeout API puts the console log immediately to the callback queue.
But we are going forward with the synchronous code. JavaScript runtime is going forward with synchronous code. So once setTimeout is taken out of the stack, the second synchronous statement is put on it, which is say something nice and vocation.
Inside say something nice, we call the console log. And this is why the "Nice to meet you," is printed before the "Hello John." So once all of our functions returns and the stack is empty event loop picks up the first available statement in the callback queue, which is console log and puts it, onto the stack.
When the stack is executed synchronously, then "Hello John," is printed to the console. Let's go to the case study, which I prepared for you today. I'm going to show you using this API, how you can perform REST API calls with JavaScript. The series of REST API calls with in different techniques of working with a synchronous actions.
So this API introduces three endpoints.
First one is directors.
This is where you can retrieve the list of movie directors like James Cameron, Quentin Tarantino, and others. The second end point is returning the list of movies directed by directors specified by his ID number. The last endpoint, the third endpoint, returns information about reviews of the particular movie. So what we are going to do today is answer the question, what is the best movie by Quentin Tarantino based on user reviews.
The first approach would be to use the request library. The request library gives us a method which accepts up to three parameters.
First one is the URL which we want to query, second one is our options.
In our case we are telling request that response, which we are expecting is in JSON, and the last one is a callback function, which we will execute when the response, HTTP response will come to the programme or error response will come to the programme. So this snippet would print just the list of directors for further processing.
Let's check out what is the best movie by Quentin. So first we need to obtain the Quentin ID.
Once we have it, we can query it for Quentin movies. When we have those movies, we can iterate through each element of the array, through each movie and query for this movie reviews. When we have this reviews, we can calculate an average rating for each movie. Once we have all averages in place, we can sort the array of movies and print out the first element.
So what is the best movie by Quentin Tarantino? This follow solution is fully functional and working, but it have one big problem.
This problem is called pyramid of doom.
As you can see, we have a lot of nested levels here. In fact, we performed just three REST calls, which led us to eight nested levels.
Let's get rid of them.
To do that, instead of passing through the callback and anonymous function, we will pass a reference to the function, which is declared before the request is performed. So in such case, when we are invoking director's standpoint, we are passing the reference to the fine director method. We implement it before invoking request.
Inside find director.
Once we have the Quentin's ID, we are invoking the request to the director/ID movies and pass the reference to the get reviews as a callbacks.
Inside get reviews, we are iterating through movies array and request for the reviews of each movie and pass a reference to the calculate average score function.
Inside that function, we are calculate an average, sorting the movie array and printing out the verdict about which movie is best basing on the reviews. So this is the final solution.
But from getting rid of nested levels, we run into another problem.
The logical order of this file is reversed. It should be read from the bottom to the top. So it's not so easy to maintain, but the process that we can reuse, the functions, which we write with other REST calls.
If you would like to follow offline those two examples, you can navigate to this link.
The first one which you can see right now is about understanding callbacks, event loop mechanism and so on. The very basics of asynchronous JavaScript. The second one is about organising your callbacks to the readable form to more maintainable and reusable form within your programme.
Let's move to promises.
Another approach of working with asynchronous action. What promises is an object representing some action, which will eventually will be completed in future. Completed or failed.
Right now you can see a very basic example of setting up the promise.
What we are doing here is calling a promise constructor with one parameter, which is a function which should be called when we want the listener to notify that the asynchronous action has been finished, and those are the results of this action.
What is the pros of promises, is that you can have as many listeners at you need to, so you can place those listeners in different parts in your programme.
In other words, your promise the asynchronous action, is not tightly couplet with the callback, with the listener who is dealing with the asynchronous action results.
The pitfall is that promise can be executed or in other words can resolve only once.
When you resolve the promise, that's the end of its life cycle.
So such code will compile and work fine.
The problem here is that the secondary resolve will be ignored.
It will be silently ignored without any warning or issue. Okay, what about the failed asynchronous action? What if you want to notify listeners that something bad occurs? Here you need to use the two parameters constructor. The first parameter is as in previous example, the reference to function, which resolves the promise.
While the second parameter is reference to function, which is invoked when you want to reject the promise. So inform the listeners about failure.
If you want to deal with such situation, if you want to catch that error within the listener, you have two ways you could do that.
First one is to pass to the then method.
Two parameters, the first one is a callback, which will be executed when promise would success, and the second one is when promise rejects. Another technique is to chain the promise, and this is important word.
We are going to cover chaining quickly.
To chain the promise with the catch method. And inside the catch method, you are passing a reference or a function, an anonymous function, which should be fired when promise rejects. Another way of notifying the listeners that action failed is to throw an exception from promise.
This code is completely okay.
It will compile and we'll be working in production. But what you need to be aware, that you cannot use the try catch mechanism to deal with rejected promises. This code will lead you to the unhanded promise rejection warning, and the statement inside the catch block, won't be execute when your promise rejects. Let's go to the promise chaining.
So in our case, in this case study, we have two promises. Promise one which resolves immediately with value three and the reference to the square method to which accepts one parameter and returns the promise, which represents the square of past the numbers. So number multiplied by itself.
If you would like to get the square value of three, you could embed the square, the invocation of square method inside the then on the promise one.
But that leads you to the nested levels, which we would like to avoid.
Thanks to the chaining technique.
And to that, that then in fact returns another promise, you can within the callback function pass in first then return the promise returned by the square function.
And at the very end in the second then, we can console log that value, which would be in both cases nine.
As I said, you can also chain your promise with the catch method, which also returns the promise. So if you will have a promise chain with multiplies then and catch at the very end, you will handle the possible error in all of the promises, preceding the catch statement.
You need also to know and be aware that one catched error won't be propagate further. So in this case only the first catch statement will be executed.
Another way of working with multiple promises, not only chaining them is to combine those. So let's say you want to wait for multiple REST responses like we are doing when we are waiting for user reviews of each movie.
You could use the promise all method.
This method accepts as a parameter, an array of promises, and returns the promise of array and that array represents values of each promise, which you passed to the method.
The problem here is, that if even one of the promises passed as a parameter reject, then the whole promise returned by promise all, rejects.
You could bypass that by chaining your promises with catch statement and return some default value or value which will be formed that this particular promise failed.
In this case, we will print an array which contains three, four integers and undefined, which says that the one of the promises rejected. The another way of dealing with such action, is to use the all settled method on the promise object. Because those snippets has been written in node.js environment.
I need to use the shim, which will enhance the promise object with the all settled method.
But this method is available in most of the browsers currently available on the market.
What all settled will return is an array containing information about the promise status and the value which is returned or rejected from the promise.
What is the reason of the rejection? Another way of combining the third one, which I would like to show you today, is using the race method.
So this is where you would like to find out the fastest promise.
Let's say you are querying different weather API for current temperature.
You don't need the information from all of them, you just need the fastest one.
So this is when you would use race.
The pitfall with race is as in the promise all. So even if one of your promises would fail, then the whole promise race will fail.
To bypass that, you can use the similar technique as previously and chain your promises with the catch statement.
But I don't want to get information that this promise is fastest, but it just failing. I want to get the fastest, success results. So in such case, I am chaining my promise with catch which returns promise that never resolves. But here I can run into some issue.
My promise race could never ever resolve.
So let's say I want to set up a timeout for two seconds. So I want to wait for my promises to resolve one of them two seconds no more.
So in such case, I can introduce the watchdog function, which returns the promise that rejects after two seconds. So if my promise race will reject, I know that it hits the timeout rather than one of the APIs, which I am calling, failed to response.
Let's use that knowledge to answer the question from the case study.
So what is the best movie by Quentin? So we are going to use the fetch method.
It's a available in all of the browsers, but as I said, I'm working in node.js.
So I need to use the node fetch equivalent. On my end, I'm going to use node fetch library. As I said, I am working in node environment. So I need an equivalent of fetch available in all modern browsers currently available on the market.
So fetch accepts one parameter, which is the URL, which I want to query to which I want to perform HTTP GET request and returns and promise representing the HTTP response for my query.
Once I have a list of directors, I'm looking for the Quentin Tarantino ID and again, use fetch and return that promise returned by fetch to next I, in my promise chain.
So within that next I, that next piece of chain, I am looking for the reviews of each particular movie and associate those reviews together with the movie title. At the very end, we are returning the promise all. As you can see, we put the promises representing requests to each movie review into the reviews array. And this array we are combining into one promise to get all of the reviews, so we are able to calculate an average score in the next piece of chain and determine which movie is best by returning the sorted array of movies.
This is how this programme works on the scheme showing the communication between node.js and API. So first node.js queries directors and point. And in return we got a promise.
When this promise resolves, we are querying the directors/two/movies to get list of Quentin movies.
And in results, we got a response representing another response. Once this promise resolves, we are performing three REST calls and put it into the reviews array.
When this, we are passing this array to the promise all, and when the function representing all of those call results, we can calculate an average, pass it to the next block in the chain and print out what is the best movie by Quentin Tarantino.
If you would like to follow offline the promises, you can go on to the, with this article, which will introduce you to promise basics.
Later on, you could try the advanced promise techniques. And finally, you can follow with the posts will show you how to refactor your callbacks into promises.
So it will show you our case study to determine what is the best movie by Quentin Tarantino. Let's move forward to next technique of working with asynchronous action.
Because so far we covered the single action promises and multi action callbacks.
Let's take a look at something.
What combines those two functionalities into one interface. And this is RxJS.
You could think about RxJS as an object, which could represent the streams of data like WebSockets or push notifications.
The basic interface, which you will find mostly around the internet is observable.
This is the interface, which is implemented by the RxJS objects, which are called subjects. So you will find different subjects implementations, which implements the observable interface.
To create the basic observable, you can use the observable create method.
Inside it you have a callback function on which you call the observer next method to push next the values to the listeners.
So to unmute those values to listeners.
If you want your listener to listen for those value, you call this subscribe method on the observable interface. So this code snippet would print the tick every one second. If you want in some point of time, cancel the subscription, you want your listener to know more, react to values returned by observable.
You just need to keep the subscription object returned by the subscribed method and call an unsubscribed method on it.
So this code snippet will print two times tick before after three seconds, we are unsubscribing from the observable.
But this is not the end of observable life cycle. It's still live and it's still emitting the values. So you can subscribe to it one more time in different point of time, in different part of your programme, and listen for those values.
If you want to finish the observable life cycle, you do that using the complete method on the observable subject.
At the very end of this snippet, we need to call the clearing interval to clean up the callback queue and let JavaScript runtime environment to finish the execution and close the programme. How to manipulate data within observables.
It's very simple, and the similar mechanism to promises.
The difference is, that you are not chaining observable, but piping it with the operators available in the RxJS/operators library.
One of such operator is map.
This operator accepts up to two parameters. First one represents the value and the second optional one, you don't need to pass it, represents the index of that value.
We are using this index here to determine if the emitted volume is even or odd, because we want our clock to give us a sound tick tock, rather than just tick, tick.
What if your observable or action represented by observable fails, or you want to notify the subscribers about the failure? What you need to do is simply use the error method on the observable and pass to it the error object. So our clock here is a time bomb, in fact it's a clog bomb.
So unfortunately the still alive, which is at the very end of the snippet and should be printed after 12 seconds, won't be because our programme will fail because of that fraud exception.
So if you want to catch an exception, you need to pipe your observable with yet another operator, which is catch error.
And inside this operator, you can return another observable.
In our case, we are returning an observable of one single element, which is a string explosion. So instead of having an error, which is breaking the execution programme, we will get the string explosion, and finally the still alive will be displayed. So this is how you can catch errors, deal with errors with observables.
Let's examine this code step by step on the time axis, which you can see at the very top together with each particular, second of the programme flow. The next row, which is represented by metronome, is what is done with the setInterval method. Then we have a microscope which represents the value emitted by observable.
Next we have what is inside the pipe method, how we are modifying the observable, and finally what is printed to the console. So at the first five seconds, we are printing the values, tick tock, tick tock, and the five second is where the explosion occurs. We are throwing the error from the observable, catching it inside the catch error and print to the console, the value explosion.
Thanks to that on the 12th second, we are able to print the message, which is asking if everyone is okay.
How to use that knowledge to determine what is the best movie by Quentin.
We will use the axios observable library.
As I said, I'm working in node.JS.
So I am downloading it from NPM and importing into my programme.
The access library gives me the Get method, which is performing the HTTP Get method.
I am passing as a parameter, the URL, which I want to query for data.
And in the response I gathered.
And as a response, I got an observable representing the HTTP response.
So I am able to pipe this with a couple operators, like map to get the response data, whether they're in the response containing information about Heather's status code and so on.
I am interested only in responsibility in list of directors. Once I have the list of directors, I am passing it to the next operator, which is again, map.
And we are finding here, we are changing the content of value or modifying the content of, modifying what is emitted by observable to the Quentin Tarantino ID.
Once we have that ID, we are passing it to the next operator, which is a flat map. Flat map is similar to map with the small slightly difference that map returns a value while flat map returns another observable.
This is why we are using it because we want to perform yet another REST calls.
We have a Quentin ID, so we want to query for his movies.
While we have those movies, we are modifying the output to get just the HTTP body.
When this body is passed to next operator, which is again flat map.
Inside this operator, we are creating the array of observables.
This is where we are going to put an observable representing call to movie reviews and point. This call is piped with some modifications, which are giving us instead of HTTP response, the information what is the average score of this particular movie? So this is what we are feeding our observables array with. Once this is done, we can use the combined latest method, which returns an observable representing all of those observables passed as some parameter to it.
This works similar to promise all.
Then we can map this observable from unsorted array to sorted array, basic on the average score. And finally determine which movie is best by picking up the first one and printing it out to the console.
The big pros of observables is not only that they can be repeatable.
The big pros is that you have plenty of operators, which you can use, and they are super useful. For example, the retry operator.
You could use it together with the REST APIs. And whenever this API call will throw an error, it would be retried three times before the whole observable would fail.
You can find out all of those operators under this URL, follow it, this is the very useful resource, when you want to modify your observable.
You can also go on with articles on Twilio voices. This one introduces you to RxJS parodying and observables basics in JavaScript.
The second one is about performing REST API calls with using RxJS.
So this is where we are answering the question, what is the best movie by Quentin Tarantino? And moreover, this one is one of my favourites. This is the article, which shows you how using observable you can synchronise multiple sources.
This article is about tracking International Space Station. So it's querying some REST APIs to continuously pull the data about ISS position.
And on the other hand, it's querying the Twilio SMS API to send SMS notifications to your colleagues to star geysers that International Space Station is just approaching them.
So they can go out and take a look into the sky to track the International Space Station with a naked eye. So I said that I will show you the synchronous and the asynchronous code.
The presentation title is there and back again. So let's for a while, forget about callbacks then subscribes and get rid of those.
How to perform an asynchronous action and get it as a synchronous code to make it easily readable and maintainable. This is where we can use an await statement. An await is a way of, instead of using the determinant on promises, call those promises as there would return the regular values.
It's as easy as just putting await next to the promise. Unfortunately, this code won't work.
It will give you an compilation error saying that await can be used only within the async function. So let's answer the question, what is an async function? Async function is a technique of making your code asynchronous again.
So if you will note an async next to the function declaration, then this will tell the JavaScript run time that this function should return the promise, and the return statement should be used as value, with which promise resolves.
So to use an await here and to make our code example working, the example when we want to synchronously step by step, execute the promises and wait for the results, we can just simply drop them into the anonymous async function and call that function immediately after it is instantiated.
So the results of that would be of course 20, because 10 multiplied by two gives 20.
So that's the difference.
You are introducing one nested level with the anonymous function to get rid of multiples then and passing a lot of callbacks to work with promises. Let's move to another example.
And this is an example of showing the super useful thing of RxJS and it's inter compatibility. Because you can use RxJS as observables together with async-await.
So you can easily change your observable into promise object by calling the two promise method. So once you have that promise object, you can use an await together with it.
What you need to remember, is that this promise would resolve when you complete your observable, and this promise will resolve with the last value emitted by an observable. So in this case, the output would be two.
How to catch errors with async-await.
As you know, promises can reject.
So here that's the moment when the try catch, finally statements comes to the action.
And this is how you should handle promise rejections with async-await.
Let's take a look how we can determine what is the best movie by Quentin Tarantino? So making this scope super clear and super readable. First, we are introducing our async anonymous function. So we are able to put await statement into it. Next, we are querying for directors, and we get this inside the promise returned from fetch. We are awaiting from promise result.
So under the constants directors, we have list of directors on which we can run the regular find method available in the array prototype. So under the directors object, under the director's constant, we got the regular array object containing list of directors.
So we are able to determine what is the Quentin Tarantino by calling the find method just on it.
Once we have his ID, we can await for another HTTP call to get list of Quentin movies.
When those movies are in place, we can build up the reviews call array pass it to the promise all and wait for this call resolved. When those reviews are in place, we can go through each of them, calculate an aggregate score and average score. And based on that sort our array to print out which movie is best.
So that's how final solution looks like.
Await, async-await is a great solution for working with dependent asynchronous actions, but you need to be aware about the performance before. And there is also the difference between promises and observables.
Observables are called by default.
What does it mean? The action which is represented by observable, won't to be executed until you want to subscribe to it. In promise it works differently.
The action represented by promise, will be called when the promise is declared. So here or when the promise is instantiated. So the first code snippet will take four seconds to elapse because first we are instantiating the promise, then waiting two seconds for it to resolve. And after those two seconds, we are instantiating the second promise.
The second code snippet will take two seconds to be right.
The reason is that we are instantiating promises at the same end.
So while we are awaiting for one promise, the other one is running in the background in the parallel.
If you would like to follow offline, what has been covered so far, you can go on with the introduction to async and await blog post available on Twilio voices.
And if you would like to answer the question, what is the best movie by Quentin Tarantino using async-await, use this one blog post.
Let's compare all of four techniques of working with asynchronized JavaScript together. So first, callbacks, promises and the RxJS, all of them are asynchronous.
The question comes to async-await.
From one point of view, it's a way of making your promises work synchronously. From the other side, you need to do that inside the async function. So that's the reason why I put the quotation mark next to this row.
What about the repeatability? The callbacks are repeatable.
They can represent action like WebSocket pushes or push notifications.
Promises are one-shot are single action.
So they are, they could be used with HTTP calls or something like that.
When promise resolves, that's the end of its life cycle. RxJS is a nice compromise between callbacks and promises, because it gives you an ability to do not tightly couple, your listener logic with the emitted logic while RxJS are repeatable and can represent streams of data. What about reusability? Callbacks are not really reusable.
They are the function, which is answering the data, which is picking an action when data appears in your programme is tightly couplet with the event with the data emitter. Promises are very reusable.
You can call them multiple times, the logic is not couplet.
Same approach with the RxJS.
Now let's move to data manipulation.
Inside the callbacks you are not really able to manipulate data.
You can do that only in the callback function inside the callback function, but you cannot manipulate data before it reaches that function.
In promises, you can use the chaining techniques. In RxJS observables, you can use operators together with the pipe method. What about the reuse cases? Callbacks are great for DOM Events like clicks on the buttons, mouse moving and so on. Promises are a perfect fit for REST calls, which are just a single showed actions.
So you got one response for one request.
Observables are great to represent streams of data like WebSockets or push notifications and situations when you want to synchronise two source of data.
So for example, two REST API calls.
Async-await is good for dependent operations. So when you want to perform some REST API call, depending on what you get from the previous API call. So that's a great use case for our scenario answering what is the best movie by Quentin Tarantino? Let's answer that question.
The best movie by Quentin Tarantino basing on the user reviews are "Inglourious Basterds." That's the moment when I would like to say thank you to you, and ask you for a pleasure and feel out the feedback for this presentation.
I would more than appreciate if you would share with me your opinion about the presentation, what you like and what you don't like in it. One more time, it's available for you offline on my speaker deck, and I am still available on all of those social networks. So you can follow me, please do that.
(upbeat music)