As a thought experiment imagine the following: a way to tell the JavaScript runtime to pause the executing of code on the await keyword when used on a promise and resume only once (and if) the promise returned from the function is settled:
// Not actual code. A thought experimentasyncfunctionfoo() {try {var val =awaitgetMeAPromise();console.log(val); }catch(err) {console.log('Error: ',err.message); }}
When the promise settles execution continues,
if it was fulfilled then await will return the value,
if it's rejected an error will be thrown synchronously which we can catch.
This suddenly (and magically) makes asynchronous programming as easy as synchronous programming. Three things needed for this thought experiment are:
Ability to pause function execution.
Ability to put a value inside the function.
Ability to throw an exception inside the function.
This is exactly what generators allowed us to do! The thought experiment is actually real and so is the async/await implementation in TypeScript / JavaScript. Under the covers it just uses generators.
Generated JavaScript
You don't have to understand this, but it's fairly simple if you've read up on generators. The function foo can be simply wrapped up as follows:
constfoo=wrapToReturnPromise(function* () {try {var val =yieldgetMeAPromise();console.log(val); }catch(err) {console.log('Error: ',err.message); }});
where the wrapToReturnPromise just executes the generator function to get the generator and then use generator.next(), if the value is a promise it would then+catch the promise and depending upon the result call generator.next(result) or generator.throw(error). That's it!
Async Await Support in TypeScript
Async - Await has been supported by TypeScript since version 1.7. Asynchronous functions are prefixed with the async keyword; await suspends the execution until an asynchronous function return promise is fulfilled and unwraps the value from the Promise returned. It was only supported for target es6 transpiling directly to ES6 generators.
TypeScript 2.1added the capability to ES3 and ES5 run-times, meaning you’ll be free to take advantage of it no matter what environment you’re using. It's important to notice that we can use async / await with TypeScript 2.1 and many browsers are supported, of course, having globally added a polyfill for Promise.
Let's see this example and take a look at this code to figure out how TypeScript async / await notation works:
functiondelay(milliseconds:number, count:number):Promise<number> {returnnewPromise<number>(resolve => {setTimeout(() => {resolve(count); }, milliseconds); });}// async function always returns a PromiseasyncfunctiondramaticWelcome():Promise<void> {console.log("Hello");for (let i =0; i <5; i++) {// await is converting Promise<number> into numberconstcount:number=awaitdelay(500, i);console.log(count); }console.log("World!");}dramaticWelcome();
Note: for both target scenarios, we need to make sure our run-time has an ECMAScript-compliant Promise available globally. That might involve grabbing a polyfill for Promise. We also need to make sure that TypeScript knows Promise exists by setting our lib flag to something like "dom", "es2015" or "dom", "es2015.promise", "es5". We can see what browsers DO have Promise support (native and polyfilled) here.