Kyle Simpson: The last thing I want to do, I know we're over time, but it's the last thing I want to do is I want to show you a library that I wrote called asynquence. I talked about it the beginning of the day. Because there are some really great things about promises, but there are also some really not so great things about them.
In that they don't go far enough with some of their abstractions. And I think the future of promises is that most people will continue to use promises with abstraction libraries on top of them. Promises are a really, really low level mechanism and in some of your most simple use cases, like for instance this one, it's not too much difficult.
But when you start to get into really complex, real-world code, it starts to get really tedious to create these promises all over the place and to figure out how to manually chain them together. When you start thinking about more complex tasks like, what if it's not this, then this, then this?
What if it's this, and all of these things, and then this thing and then these two things and then this thing, except go back and start, what if you start having those sorts of flow control? Promises start to get really tedious. And that's why there are promises abstraction libraries to try to help some of the tedium.
Try to take care of some of that tedium for you. There's a number of ones out there. There's Async and Q and several other ones. I happen to have one that I think does a pretty good job of making things simple and it's called asynquence. Asynquence stands for asynchronous sequences.
So sequences are automatically chained promises. If you'll notice in our previous promise examples, you had to manually create a new promise and return it from each step to keep the chain going. Whereas in most cases, you could just assume that somebody wants to keep going, because there's always another step in your task.
Most of the real world times, it's a lot more than just one step. So asynquence assumes it and it automatically creates and chains promises for you. And here is a simple distillation of the code. You create yourself a sequence by calling the constructor, the ASQ. You have your then steps, because it's just a series of then steps, but you'll notice you don't have to create promises here.
It automatically creates a promise for you and it passes in the completion trigger. So it assumes that you are going to want to go on and it creates the promise for you. And you just need to make sure to call the trigger at the proper time. You don't have to do any of that work of creating those promises for these normal steps.
It's created them underneath the covers. We also have the ability to do the other primitive in asynchronous flow control is what we call gates. So sequences are this, then this, then this, then this. A gate says, two or more things are going to happen at the same time and I don't care when they finish and in what order, I just want to wait for all of them to finish before I move on.
So it waits for everybody to get to the gates, an old school terminology from processes and fork and stuff. So asynquence lets you split from a sequence into a gate step, back into a sequence. And you can ExPlus any arbitrary complexity of flow control using the asynquence API.
For example, here's our little meaning of life example. I have rather than returning a promise, I return back a sequence. Here I can do what's called a waterfall, which does these things in order, but it keeps track of the messages. So, it calculates 10, sends that along. It calculates 30 and it sends that along.
10 and 30 come in. We then calculate the meaning of life as x and y and we pass that one along. So you can do the same sort of message passing. Just has a lot less work because you don't have to create the promises every time.
Kyle Simpson: Finally it was mentioned earlier, what about generators and promises?
I think that generators plus promises are actually the most popular pattern that we're going to move towards for asynchronous flow control. And I've got an API built into asynquence that's handled natively. It's called runner. It allows you to pass in a generator and yield out sequences or promises. So it automatically, this little runner utility, when you yield it out it will receive that promise, listen for the promise to complete, before it starts back up the generator.
So it'll automatically continue to the end for you.
Kyle Simpson: So we would yield out a promise or a sequence for getData. And when that guy sends us the value back in, then 10's going to come back in. Then we yield out another promise. A second later, we get 30 back.
We finally yield out a third promise for the string, and a second later we get that answer back. And we can return that answer, which then gets passed along.
Kyle Simpson: Along the sequence chain.
Kyle Simpson: Finally, I just want to show you something cool, because I just was starting to experiment with this.
I actually think this and unexplored territory here. The idea of taking two or more generators and interleaving their operation. So runner actually allows you to specify two or more generators, and what will happen is the first time it yields, it'll actually message pass to this generator. And when this generator yields, it will pass to the next one in a round robin fashion.
So you can actually have these generators running at the same time, starting and stopping and message passing to each other. Which is going to lead to all kinds of powerful stuff. This is called CSP, communicating serial processes. It's a really advanced model for continuation style.