Our dashboard is a medium-sized (~26k lines of code) AngularJS SPA (single-page application). Like most API driven SPAs, our dashboard makes a lot of asynchronous calls to fetch data. In many cases, we’re nesting asynchronous API calls several levels deep which has started to become a maintenance problem for our team. It’s not a total blocker, but it has slowed down development in complex parts of the code base.
The biggest benefit of async/await is that asynchronous, non-blocking code can be written to look like synchronous, blocking code. To put it another way, with async/await we can flatten our deeply nested asynchronous code and thus make our code simpler to understand, debug, and develop.
Flattening Callback Pyramids
Above is an extremely pared-down example from our code base of a callback pyramid.
Why are they called callback pyramids?
1. If you tilt your head, you’ll notice that the shape of the code outlines a triangle or a pyramid (if you want to Walk Like An Egyptian).
2. Notice how deeply nested the code is; this is inevitable when you handle asynchronous code with just callbacks.
Below is the same code, rewritten using async/await.
Beautiful, isn’t it? The callback pyramid has been flattened, and the code is easier to read because with async/await we can treat asynchronous calls like synchronous function calls.
The Power Of Babel
We’re huge fans of the Babel compiler because:
2. it’s a stable piece of software and the generated code hasn’t caused us any headaches.
After a decade of programming, one of the lessons that I’ve learned is that “simple” things are usually hiding their complexity somewhere else. This is true of Babel and its implementation of async/await. Behind the deceptively simple syntax of async/await, lies a cave filled with a thousand dragon books.
Below is the async/await code from earlier, after it has been translated by Babel. I’m not a compiler wizard but I have built a few toy compilers, and it seems like Babel is transforming the async/await code into a Continuation-passing style. I applaud the Babel team because I can’t imagine how much work went into this feature.
Although it's a complex feature that ends up generating more code than the original non async/await example, I do think the trade-off is worth it. Developers can focus on building features while the machine takes care of the asynchronous plumbing.
I’m pleased to report that enabling async/await in Babel was a breeze and that async/await has been running in production for the past few weeks with no issues. Async/await has not only allowed us to tame our callback pyramids, but it has also changed the way that we think about asynchronous code. It’s always exciting to find a tool that makes your job a little bit easier, and it’s even better if you can share that knowledge with others.