Using async/await with Typescript — the minimum you need to know

People are generally attracted to Typescript because the strong typing will speed up your development cycle by preventing common errors. New Typescript developers generally fit into two camps — those experienced with Javascript, or those coming from a strongly-typed language like C# or Java.

When your code doesn’t behave

If you are used to a (usually) synchronous language like C#, the asynchronous nature of Javascript may throw you for a loop. Here is an example:

Expecting synchronous behavior leads to problems

For now, just ignore the details of the “database” call and pretend it is some normal database call that takes 2 seconds. If you are used to synchronous programming, you would expect to see:

Starting
foo
done

You would notice a 2-second delay between “Starting” and “foo.”

However, if you try this out in Typescript you will actually see the following:

Starting
undefined
done

What happens is that the Javascript execution hits the line 2, starts the execution of the line 3, and then immediately proceeds to line 4. The engine will eventually finish the simulated database call but you won’t know that because you got the immediate result of the initial call, which is undefined.

In a normal C# program, execution would block on the second line until it was done and then proceed to the third line. Synchronous programming is easier to follow because it is rigidly step-by-step. However, it can have performance penalties, especially in web applications. I’ll talk about that more in a later post.

Taming the async beast (partially)

The Javascript world has come up with many ways to solve this problem, starting with callbacks and then something called promises. They all basically solve the same problem of “start this slow process and call me back when you have an answer” However, both callbacks and promises lead to code that is difficult to follow.

Luckily, the Microsoft engineers behind Typescript have been able to migrate over a mechanism from the .Net world called async/await. It isn’t a complete solution compared to async/await in .Net, but it does make async code more manageable. Async/await does work on top of promises, but you don’t really need to understand those in order to use it. Just understand that most of the common Javascript libraries that do I/O (web, database, file, etc.) generate promises, so they will work with async/await.

Here is the previous example, done with async/await:

async/await lets you think (mostly) like a synchronous developer

Again, ignore the details of the simulated database call. If you use a popular Javascript library it will work just fine with async/await and you won’t have to think about it. If you run this example, the output will be exactly what you expect to see from a synchronous program, but it will be running asynchronously.

At a minimum, there are only two things you need to notice here. The first is the use of “async” to mark the function as an asynchronous function. That’s mandatory. If you don’t do it, the Typescript compiler will complain and your code won’t work.

The second thing is “await.” That basically means “wait at this line and don’t continue to the next line until it is done. You might be tempted to think of this as turning an asynchronous function into a blocking call. But that is not what is happening at all. When the execution hits “await” it won’t block — it will effectively just mark that location as a placeholder while the Javascript engine goes off and processing other things (web calls, animations, whatever). You may or may not care about that, depending on your program, but ultimately it doesn’t matter. Unlike .Net, you are stuck with asynchronous programming for I/O with Typescript/Javascript. There is no way to turn it back into blocking synchronous code — just not possible. But async/await make it a lot easier to deal with.

Next post: why async programming is important