ES6 Series: Async Javascript.

Javascript is single threaded, that means that only one thing can be happening at a time. It is kinda like a straw. When I am sucking on a peach smoothy and a chunk of peach gets stuck in my straw I can’t get any more goodness. That is the problem with single threaded JS.

If I keep going with that analogy, multithreaded is kinda like a soda helmet:

multiple sources through a single straw.

Several other languages have that, but not javascript (well, that isn’t completely true with web workers, and I’ll write up something on that later), but javascript has a different concept. It is kinda like a table full of sodas with straws. You only have one mouth, but you can jump from soda to soda.

That is where the asynchronous model comes into play. There are a few key concepts to understand to see how you can utilize delayed processing and asynchronous benefits. The ones we are going to talk about are Custom Events, Promises, and Generators. In that order, from most familiar to least familiar.

Custom Events

Events should be really familiar to you. We deal with them all the time, in the DOM you have clicks, scrolls, moves, touches, loads, and more, in server you listen for connections and http events and respond to them. Events are at the heart of javascript, right next to prototypes. It is the observer pattern, meaning, I am listening for something to happen, when it does I am going to do something. We refer to them in JS as listeners and handlers.

Here is a simple example of a generic event, and one that removes the element that get clicked. (Notice the use of an arrow function and e.target instead of this, if you need a little refresher on arrow functions you might want to look at ES6 Series: Arrow Functions) When the user preforms the click on the element then the handler is run. But nothing happens until that event is called. It is like the soda sitting on the table, waiting to be drunk.

Now, we know a lot of events that happen on user input, but how did that event come to be, or, how can I do that? Let’s get into that with custom events!

With that code you are registering a function to be run when the someobj receives the ‘customEventName’ event and passing what ever values you want along with it. That event is then being dispatched and if someobj is in the capture or bubble phases of the event then it will run the function. Cool.

What this means is you are pausing the calculation on that process until something else is fired to tell you that you need to think about it. That is a really important part of thinking in async, what processes can be run while I am waiting, and what can be paused now that doesn’t need to be running.

Just a closing note on custom events, when I started I thought they were for things the users did, click, swipe, all that stuff, but that are really for anything you need to have happen based on reactions.

Promises

Where events are good for broadcasting, promises are not, but some of the concepts are similar and they are a lot better at other things. As we start with promises I want to start with the callback pattern. Most likely you have had experience with callbacks, but may not have known it.

The place I used that pattern the most was with ajax calls and jQuery. Here is a different look that may look more familiar.

What happens is that you pass a function in, and because we are JavaScript we can do that, you can then call the function remotely and it still understands context of where it was defined from. Really powerful pattern. One of the issues is that it is synchronous by nature, even though it is remote. A promise has a similar principle. It allows you to call from a remote and execute local, but it is asynchronous.

The promise is created with a function passed in, it accepts two params—resolve, and reject, shortened here to res and rej—that get called when you want the promise to finish. A reject will call the catch in the chain, a resolve will go to the .then.

The .then returns a promise, so it can be chained. A value you return in the passed in function becomes the value in the next link in the chain.

Where this is awesome is that, returning back to the original analogy, it allows you to move from one straw to another until you need it again. This allows the script to run more efficiently.

And one more really awesome thing about promises. If you have multiple and need to do something when all of them, or the first one, is finished there are some built in function for that.

The Promise.all function is really useful because you can send out a bunch of things at the same time and they can all be working towards the end at the same time, then when they are all done, it resolves.

There is a downside to both callbacks and promises. In order to interact with the returned values you need to be inside the function. Take this for example:

Above someFunction will always return an empty string because the promise doesn’t stop the function from running. It will start, run line 3, then line 5, then line 9, then the promise will resolve. It also doesn’t have a shared scope between resolved promises. Sometimes you want and need a promise to act like a normal variable. That is where async & await come in.

Let me demonstrate with showing the three patterns next to each other:

One of the problems with async & await at the moment is there is no access to Promise.all with the awaits so they all fire one after another. Even so, that is pretty powerful! And we still have one more pattern to go through.

Generators

I must admit, this one is the hardest to wrap your brain around, but it is what async & await are based on. Even though these are little hard, generators are awesome. There are a few building blocks, the function statement, yield, and return.

The function statement has a * in the declaration like this: function *myFunction or function* myFunction both are valid. I like having the * next to the function declaration, but I don’t think it really matters either way.

The yield and return act as the same thing almost. Think of a yield as a return statement that you’ll come back to. The return marks the generator as “done”.

Are you ready for it? Here is some code:

Let’s walk through what is happening here. First, I am defining ‘someFunction’. Then I am calling it, passing in the param of 5. That will go to the first yield and return a*2. That goes to line 14 where I am requesting the first yield statement. That passes back an object {value: 10, done: false} which I am pulling the value from and putting into a variable called first. Then I call sf.next again and pass it the value of first * 2 which is 20. That gets put into ‘someFunction’ at the first yield. So that is setting x to 20. ‘someFunction’ then continues to the next yield statement at which point it returns x*2 so it returns to line 15 with the object of {value: 40, done: false}. That gets put into second and we continue.

The pattern that I hope you can pick up is that the value that gets returned in the yield is what gets passed out of the function, then what ever you pass back in through the .next() call replaces the yield. That is the part that is important to get your head around.

The last thing to wrap up on how it works is that the return passes the object {value: 32, done: true} That done means that no more yields will be called. It has finished.

Two final cool parts and patterns. There are two things that I want to call out specifically when it comes to generators. First, having a while(true) may be exactly what you want. For example:

In this fibonacci sequence function I have a while(true) loop. Why? Wouldn’t that be infinite. Yes and no. Because I am pausing the function in the yield it will not move to the next loop until I ask it to using fib.next(). So yes it is infinite, but no it will not cause problems because I can tell it when to proceed and that may be exactly what I want in a generator.

The last thing I want to bring out is the for…of statement. This is a cool little thing for generators, though, like any tool, is only cool when it is exactly what you need. So here is the code, then well talk about it, then this article is…over.

So, that is the for…of loop. Pretty cool. It essentially iterates over each yield in the function until it returns {done: true, …}. That is important because, as you’ll notice with the example, only three numbers were returned. That is because when the for…of loop gets the ‘done’ flag, it stops and doesn’t go another round. So the return statement is ignored.

The other thing to notice is that there is no way to add a value back into the function like there is with the .next(val) syntax.

And with that, we are done. Now you can go and become an async master!


Don’t forget to checkout out the rest of the ES6 series articles, or the next article: Fetch.