Note: This blog post is inspired by the following two excellent videos. I think it will be more beneficial for you to watch those.
- Promises and Generators: control flow utopia – JSConf EU 2013
- Hanging Up On Callbacks: Using ECMAScript 6 Generators
I have made some changes to deal with the general use-case of multiple
jQuery based ajax calls, but for the most part, this blog post is just a learning exercise for me.
I like reading, and learning, a lot. I also recently quit my day job, where I was working overtime (by choice), doing not just my own work, but also helping almost everyone else out with their programming problems. This was fun as long as people came to me with hard problems that they couldn’t solve; at least, not in a reasonable amount of time. I enjoyed that part so much that I almost never complained about being underpaid. As long as I could get my hands on some cool problems, money was not an issue. The bad part was that, since I was so accomodating, I was sometimes asked to solve problems that were just plain silly. That was a bit aggravating.
Even though I was working overtime by choice, I did miss a few things like long learning/programming sessions and leisure reading. Don’t get me wrong. I learned a lot on the job. I did learn a lot by solving other people’s problems. Sometimes those problems took up my weekends. But I was getting more and more busy. Having 2 days straight just for learning/programming was a luxury. I like learning things in detail. I like getting to know the internals of things. I had been thinking of quitting the job for quite some time, and then, the company moved to a new office; and they decided that open office plans were a great thing. They probably had never read peopleware. I couldn’t stand working with so much visual and auditory noise. 1 month later, I resigned.
So, you might be wondering what does this have to do with the
ECMAScript generators. Well, nothing really. The thing is, after quitting the job, I have been doing some freelance work, which pays way more than my job and I still get more time to learn new things. So, I have been bingeing on all kinds of learning resources: books, articles, videos. That’s how I got to
IE 6 compatibility. It has come a long way from those days.
ECMAScript 6 is still not very widely implemented yet. If you want to execute the code, the latest versions of Firefox or Chrome would be obvious choices. If you want to checkout the implementation status of
ES 6 for various browsers, check out this compatibility index.
The control flow in asynchronous coding
Okay, this is not yet very ugly. However, add one more nested ajax call, and you enter the proverbial callback hell. Instead of nesting, if you want to execute those ajax calls in parallel, you could do something like this:
Again, this is not very hellish; not pretty either. Things are made a bit easy by
jQuery.when. However, it’s far from the normal flow of code that programmers are generally used to. We don’t have
try-catch and we handle the errors through callbacks. We might need one error handling callback for each asynchronous operation. You might still need additional error handling when dealing with the results of successful asynchronous operations. For ex. trying to parse the response of a request could throw an exception and you might need a
try-catch for that. So, your error handling code would be a huge mess of error-callbacks and possibly multiple
Generators to the rescue
They have the capability to suspend their execution context and then later re-enter that execution context with variable bindings intact across the re-entrances.
If you don’t know the basics of generators already, here’s a quick rundown of the basics:
* just before the function name. That’s what makes this a generator function. When you call
rangeGenerator(), it returns you the actual generator object that you can use to get to the generated values. When a
yield statement is encountered, the result of evaluating the expression on the right-hand side of
yield is returned and the execution context is suspended. Each call to
range.next() returns a JS object with two properties:
value is the actual value that is returned by the
yield statement, and
done is a boolean flag indicating whether the generator is done producing results. You can easily use this flag to get all the values from a generator using some form of a loop. Or, you can directly iterate over them using the new
for...of loop, as can be seen in the example. You can do all kinds of cool stuff with generators. For ex. you can use them to create infinite sequences.
You can go even a step further and define operations like
map to be lazy. Alright, so, as far as using generators with async operations is concerned, there are two important things to keep in mind about generator.
- You can inject values into a generator by passing an argument to the
next()method call. If you do so, the value passed to the method call would be the return value of the last
yieldstatement that resulted in a value.
- You can call
throw()method on a generator. The exception object passed to the
throwwill be thrown from the current suspended context of the generator, as if the yield statement that is currently suspended were a
The following sample should probably explain it a bit more clearly.
Keeping these two things in mind, a generic utility method could be created that would allow us to handle the jQuery ajax code in a much more natural, and easy to manage manner. We would make use of the
async function defined below. This function is inspired by the contents of the two videos mentioned at the beginning of this post. Of course, I have made a few changes, and corrected a mistake.
So, how do we use this. Well, pretty simple. If you want to have multiple async calls executed one by one:
This is much more readable then any callback based mechanism we might come up with. It also has the advantage that the errors can be handled in a more natural way. No multiple
try-catch blocks, no error-callbacks. Just a straightforward
If we want to execute these calls in parallel, we can do that as well.
Notice that all the ajax calls start in parallel. Notice especially the position of the
Generators do look like a great feature. As more developers become faimiliar with it, I think they will come up with even more usages for them.
- ECMAScript spec. Still in the draft stage.
- ECMAScript Generators Spec
- MDN documentation for generators
- jQuery promises
- Summary of new features in ES 6
- Summary of ES6 compatibility in various browsers