Using the TypeScript 2.1 async/await construct in Aurelia

During the week, TypeScript 2.1 got promoted to release candidate. One of the interesting things in TypeScript 2.1 is the ability to now use asynchronous functions (async/await) when targeting ES5 and even ES3.
TypeScript async await with Aurelia

Previously it was possible to use async/await in TypeScript, but it was only supported when targeting ES6.

As an old C# coder, this is something I have been looking forward to. When learning TypeScript/JavaScript I remember longing for the simplicity of async/await every time I had to use callbacks or promises 🙂

Using async/await in Aurelia CLI Web Apps

Out of the box, an Aurelia CLI project is setup to use ES5. Can we sprinkle some TypeScript future magic on our Aurelia project and start using future JavaScript features today? But of course we can! 🙂

Add references to the TypeScript RC

First off, we need to install the TypeScript RC. As I’m using Visual Studio Code, I want to install it globally to enable the language service in VS Code to use it. And we also want to install it locally in the project. Run the following in a CLI, from the root of your project:

npm install -g typescript@rc
npm install typescript@rc

Using async/await in a method

Let’s rewrite a method with a promise to use async/await. I got this method that uses the Aurelia Fetch client to get some data from a server. The original method looks like this (the method is from the article series about writing an Aurelia SPA):

import { HttpClient } from 'aurelia-fetch-client';
import { autoinject } from 'aurelia-framework';

@autoinject
export class App {
    public header = 'Droids';
    public droids = [];

    constructor(private http: HttpClient) {
        console.log("Init App.ts");
        http.configure(config => {
            config
                .useStandardConfiguration()
                .withBaseUrl('http://localhost:5005/api/droids');
        });
    }

    activate() {
        console.log("Fetching droids");
        return this.http.fetch("")
            .then(response => response.json())
            .then(droids => this.droids = droids);
    }
}

First off, let’s move the fetch out of the activate method to keep it clean. Let’s also sprinkle some logging so we can see what happens.

    activate() {
        this.fetchData();
    }

    private fetchData() {
        console.log("Fetching droids");
        return this.http.fetch("")
            .then(response => response.json())
            .then(droids => this.droids = droids);

        console.log("droids:");
        console.log(this.droids);
    }

Transpiling the code and running it yields the following result in the console:

Fetching droids
droids:
undefined

As per expected, the droids aren’t fetched yet as the method finishes, so droids returns undefined. However, the promise returns the result later, and populates the UI as expected.

Modifying a method to use async/await

If we modify the fetch to use async/Await, we expect the droids array to contain a result and be able to log it in the console at the end. Let’s modify the fetchData method by marking it as async, then using await on the asynchronous bits:

    private async fetchData() {
        console.log("Fetching droids");

        let response = await this.http.fetch("");
        this.droids = await response.json();

        console.log("droids:");
        console.log(this.droids);
    }

Transpiling the modified method and running it yields the following result in the console:

Fetching droids
vendor-bundle.js:11987 DEBUG [templating] importing resources for app.html ["resources/elements/droid-tile.html"]
droids:
[Object, Object, Object]

Success! The droids are now fetched before the method returns, and we can log the result as expected.

And another really cool thing here is that we see the async method yielding control for a moment and the Aurelia framework taking the opportunity to load a html template while the data is transferred from the server.

Debugging Caveat

Do note that if you are using a browsers DevTools to debug your code, the sourcemap debug stepping isn’t going to work as expected.

Benefits of using async/await in TypeScript

There is a few clear benefits in using the async/await pattern in your TypeScript code:

  1. One clear benefit is how terse the code becomes. Just look at the example above to see the difference, and that’s a very small promise chain, imagine it being production code and ten times as long.
  2. Terser code leads to lower cyclomatic complexity.
  3. The result of the code terseness and easily identifiable result after each await, is that error handling becomes easier and cleaner. The above fetch example is very simple, but a robust fetch call with error reporting etc is easily 30-50 lines of code depending on how many status codes there is need to handle. And that kind of code is not so easy to follow.
  4. Big enterprise will have an even easier time recruit, or shift over, c# devs to new TypeScript projects.

That’s all for this time, write a line below if you enjoy the new async/await goodness!

Happy coding! 🙂

Using TypeScript’s async/await in Aurelia
Tagged on:         

4 thoughts on “Using TypeScript’s async/await in Aurelia

    • November 25, 2016 at 22:18
      Permalink

      Yeah, slick isn’t it?! 😎

      Reply
  • December 8, 2016 at 22:48
    Permalink

    Cool, but I’m concerned about debugging stepping problems – is it possible to somehow avoid them?

    Reply
    • December 8, 2016 at 23:18
      Permalink

      Not right now as far as I know, but when the browsers start support it, the problem will be solved.
      I think Chrome 55 have async/await support implemented already, so it’s not far off.

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *