How TypeScript's async/await Makes Your Life Easier

Tuesday, December 29, 2015 by Rainer Stropek

Many of our customers use Node.js to extend time cockpit. They automate routine tasks, implement interfaces to other systems, or even write powerful web apps on top of time cockpit's OData web api. We have good news for you: TypeScript's new async/await feature makes your life much easier.

You want to learn more about what you can do with Node.js and time cockpit? Search for "Node.js" on our website to find related articles.

Introduction

In modern web development platforms like Node.js or ASP.NET 5, all long-running functions are asynchronous. I use both platforms depending on the needs of the particular project. ASP.NET makes it very easy to deal with asynchronous methods as C# has been offering the async/await keywords for years. Until recently, asynchronous code for Node.js was much harder to write even if you were using TypeScript instead of JavaScript (what we do at time cockpit). The async module helps a lot but as somebody who comes from a C# background, I was deperately longing for async/await.

End of November 2015, Microsoft released the 1.7 version of TypeScript. It supports async/await for the ES6 target. You can use it e.g. for Node.js (you will need at least v4).

Sample

Here is a short samples that shows how you can use TypeScript's async/await in conjunction with time cockpit. It uses the Needle module for sending HTTP GET requests to time cockpit's web api. Take a look at the method getCustomersPerCountry. It demonstrates the power of async/await. The method is written as it would be using just synchronous methods. In fact it uses multiple async methods but async/await is hiding all the complexity.

/// <reference path="typings/tsd.d.ts" />
import * as needle from "needle";
import * as chalk from "chalk";

// Some constants for configuration
const tcBaseUrl = "https://apipreview.timecockpit.com/";
const tcUser = "demo@timecockpit.com";
const tcPassword = "...";

interface ICountry { APP_IsoCode: string; }
interface ICustomer { APP_CompanyName: string; }

// Note how we wrap the needle.get calls in the following two helper functions using a Promise
// (see also https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Promise)

function getTokenAsync() {
	return new Promise<string>((resolve, _) =>
		needle.get(
			`${tcBaseUrl}token`,
			{ username: tcUser, password: tcPassword, auth: "Basic" },
			(_, resp, __) => resolve(resp.body)));
}

function queryTimeCockpitAsync<T>(odataPath: string, token: string) {
	var headers = { accept: "application/json", Authorization: `Bearer ${token}` };
	return new Promise<T[]>((resolve, _) =>
		needle.get(
			`${tcBaseUrl}odata/${odataPath}`, 
			{ headers: headers },
			(_, resp, __) => resolve(resp.body.value)));
}

// The next function demonstrates the power of async/await in TypeScript.
// As you can see, the function is written as it would be synchronous.
// The "await" keyword is caring for all the magic necessary for async processing.

async function getCustomersPerCountry() {
	var token = await getTokenAsync();
	var countries = await queryTimeCockpitAsync<ICountry>("APP_Country?$select=APP_IsoCode", token);
	for(var i = 0; i< countries.length; i++) {
		var country = countries[i];
		console.log(chalk.bgGreen.white(country.APP_IsoCode));
		var customers = await queryTimeCockpitAsync<ICustomer>(
			`APP_Customer?$filter=APP_Country/APP_IsoCode eq '${country.APP_IsoCode}'&$select=APP_CompanyName`,
			token);
		customers.forEach(c => console.log(c.APP_CompanyName));
	}
}

getCustomersPerCountry();

comments powered by Disqus