├── .gitignore ├── 00 overview └── README.md ├── 01 why ├── README.md ├── src │ └── index.ts └── tsconfig.json ├── 02 promise ├── README.md ├── src │ └── index.ts └── tsconfig.json ├── 03 async ├── README.md ├── src │ └── index.ts └── tsconfig.json ├── 04 flow ├── README.md ├── src │ ├── getUserDetails.ts │ └── index.ts └── tsconfig.json ├── 05 forAwaitOf ├── README.md ├── src │ ├── index.ts │ └── server.ts └── tsconfig.json ├── README.md ├── cover.png ├── package-lock.json └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | # IDE 2 | .alm/ 3 | node_modules/ 4 | -------------------------------------------------------------------------------- /00 overview/README.md: -------------------------------------------------------------------------------- 1 | # Introducing async / await using TypeScript 2 | 3 | > Here's a little intro to the course material. I hope you enjoy the course! 4 | 5 | ***Play a video of the first lesson*** 6 | The goal of this `async` `await` using TypeScript course is to help you understand and appreciate how simple asyncronous programing has become thanks to the runtime features provided by JavaScript and the Compile time understanding of your code provided by TypeScript. 7 | 8 | ***Play video of promise lesson*** 9 | We kick off by taking a basic look at promises. This is because promises are fudamental to async await. However we don't add any noise by going deep into promises as a lot of the complex rules around `then` and `catch` callabacks are greatly simplified by using `async` `await` 10 | 11 | ***Play video of async await*** 12 | So after a quick recap of promises, we take a look at how the async and await operators interact with promises. 13 | 14 | ***Play video of execute promsies in parallel or serial*** 15 | Finally we look at a few additional patterns surrounding async await, such as the default serial execution, parallel control flow using `Promise.all`, along with asynchrous iteration using for-await-of. 16 | 17 | ***Slide with course image*** 18 | I'm very excited about the code analysis and error checking offered by TypeScript when doing async / await. I hope you can see how fluently I can present this material as I always have TypeScript watching my back and making sure I don't make any simple human mistakes. I can't wait to see what you build with this powerful and reliable combination of TypeScript with async/await. 19 | -------------------------------------------------------------------------------- /01 why/README.md: -------------------------------------------------------------------------------- 1 | # Simplify asynchronous callback functions using async/await 2 | 3 | > Learn how to write a promise based delay function and then use it in async await to see how much it simplifies code over setTimeout. 4 | 5 | > Lets say you want to call a function after 1s, 2s, 3s. You can use setTimeout, or you can wrap it up into a simple delay function that works with async/await 6 | 7 | Lets say we have a requirement to run a function after 1s, then 2s, then 3s. 8 | 9 | * A quick way to write the run function is using setTimeout. 10 | * we can take are required function as a callback within our runner and internally we can just use settimeout to call this callback after a second. 11 | * It takes a callback. Sets up our settimeout to call it after 1s. And then we repeat this pattern for 2s and 3s. 12 | * Next we simply pass in a callback that logs the time when it gets called. 13 | 14 | ```ts 15 | const run = (cb) => { 16 | setTimeout(() => { 17 | cb('1s'); 18 | setTimeout(() => { 19 | cb('2s'); 20 | setTimeout(() => { 21 | cb('3s'); 22 | }, 1000); 23 | }, 1000); 24 | }, 1000); 25 | } 26 | 27 | run((time)=>console.log(time)); 28 | ``` 29 | 30 | ***Demo the file*** 31 | If we run this code now we can see that it follows the specification correctly in that the callback is called after 1 second, 2 seconds and then three seconds 32 | 33 | ***Select the body of the function*** 34 | Even though it does satisfy our requirement you can see that the setTimeout nesting in our run function adds a lot of noise that makes the intent slightly difficult to figure out. We can make this much easier with async/await. 35 | 36 | The only thing we need is a promise based delay function, and that is very easy to write. It simply takes a number of `ms` and returns a Promise that gets resolved using setTimeout after the given number of ms 37 | 38 | ```js 39 | const delay = (ms) => new Promise(res => setTimeout(res, ms)); 40 | ``` 41 | 42 | Now we can create our `runAsync` function which is now an `async` function which is still going to take the callback like before. 43 | 44 | ```js 45 | const runAsync = async (cb) => { 46 | 47 | } 48 | ``` 49 | 50 | And inside the function we now get to use `await` to pause function execution till the promise is resolved 51 | 52 | ```js 53 | await delay(1000); 54 | ``` 55 | 56 | and then we call the callback passing in the time 57 | 58 | ```js 59 | cb('1s'); 60 | ``` 61 | 62 | And we repeat this twice more, simply changing the argument to the callback. 63 | 64 | ***Demo the file*** 65 | Now if we copy over the previous call to run and this time call run async if we go ahead and execute the file you can see that it still behaves the same in that the callback is called after 1s, 2seconds and then 3seconds, but this time the code is much simpler thanks to our promise based delay function and async await. 66 | -------------------------------------------------------------------------------- /01 why/src/index.ts: -------------------------------------------------------------------------------- 1 | const run = (cb) => { 2 | setTimeout(() => { 3 | cb('1s'); 4 | setTimeout(() => { 5 | cb('2s'); 6 | setTimeout(() => { 7 | cb('3s'); 8 | }, 1000); 9 | }, 1000); 10 | }, 1000); 11 | } 12 | 13 | 14 | const delay = (ms) => new Promise(res => setTimeout(res, ms)); 15 | 16 | const runAsync = async (cb) => { 17 | await delay(1000); 18 | cb('1s'); 19 | await delay(1000); 20 | cb('2s'); 21 | await delay(1000); 22 | cb('3s'); 23 | } 24 | 25 | runAsync((time) => console.log(time)); 26 | -------------------------------------------------------------------------------- /01 why/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": [ 4 | "es6", 5 | "dom" 6 | ], 7 | "outDir": "lib" 8 | }, 9 | "include": [ 10 | "src" 11 | ], 12 | "compileOnSave": false 13 | } 14 | -------------------------------------------------------------------------------- /02 promise/README.md: -------------------------------------------------------------------------------- 1 | # Promise fundamentals using TypeScript 2 | > Learn the fundamentals of creating, resolving and rejecting promises using TypeScript. We also cover the fundamentals of a *then chain*. 3 | 4 | ***Have the demo window open*** 5 | 6 | At the heart of async/await is a Promise chain. To create a promise chain we need to start off by creating a Promise. 7 | 8 | * The promise constructor takes one generic type for its resolved value. Lets use the `number` type for now. 9 | * The constructor takes an *executor* callback which will be called by the runtime with two arguments. 10 | * The first argument is a resolve function that can be used to resolve the promise. 11 | * The second argument is a reject function that can be used to reject the promise. 12 | ```js 13 | const example = new Promise((resolve, reject) => { 14 | // Use resolve or reject to determine the fate of the promise 15 | }); 16 | 17 | ``` 18 | * There are two fates of a promise, resolved or rejected. 19 | * Promises have two member function's `.then` and `.catch` that are invoked depending upon the fate of the promise. 20 | ```js 21 | example.then(value => { 22 | console.log('then', value); 23 | }); 24 | 25 | example.catch(error => { 26 | console.log('catch', error); 27 | }); 28 | ``` 29 | * If we `resolve` the promise, any `then` callbacks are executed. 30 | ```js 31 | resolve(123); 32 | ``` 33 | * If we `reject` the promise, any `catch` callbacks are executed. 34 | ```js 35 | reject(new Error('failed')); 36 | // throw 'message' => bad 37 | // throw new Error('message'); => good 38 | ``` 39 | ***Select the new Error*** 40 | A promise rejection should only be done in exceptional circumstances, and just like it is bad practice to throw a raw string, it is bad practice to reject a promise with a raw string. Always use the error constructor `new Error` when rejecting a promise. 41 | 42 | ***Delete all the code*** 43 | Alright, now that we understand the fundamentals of promise creation and its resolved/rejected fate, lets look into the concept of a promise *chain*. 44 | 45 | * The `then` function creates a new promise. 46 | * This new promise is distinct from the original promise 47 | * We can verify that by simply comparing it to the original promise. 48 | ```js 49 | const first = new Promise((resolve, reject) => { 50 | resolve(123); 51 | }) 52 | const second = 53 | first 54 | .then(value => { 55 | // Control the fate of second 56 | }); 57 | 58 | console.log(first === second); // false 59 | ``` 60 | 61 | ***Delete console.log(first === second); // false*** 62 | 63 | * This second promise is entitled to its own then and catch callbacks if you want. 64 | ```js 65 | second.then(value => { 66 | console.log('second then', value); 67 | }); 68 | second.catch(error => { 69 | console.log('second catch', error); 70 | }); 71 | ``` 72 | 73 | ***Select the body of first then*** 74 | If the original first promise resolves, the fate of this second promise is determined by the body of the `then` callback. 75 | 76 | * If you return a value from the callback, that becomes the resolved value of the second promise 77 | ```js 78 | // Control the fate of second 79 | return 456; 80 | ``` 81 | * Ofcourse if you don't return a value, JavaScript implicitly returns `undefined` and that becomes the resolved value. 82 | ```js 83 | // Control the fate of second 84 | 85 | ``` 86 | If you return a promise from this callback, the resolution of this second promise is determined by the fate of this promise. 87 | 88 | * If the promise resolved, its resolved value is also resolved value the second promise 89 | 90 | ```js 91 | // Control the fate of second 92 | return new Promise((res) => res(789)); 93 | ``` 94 | * And if that return promise is rejected, then the second promise is also rejected. 95 | 96 | ```js 97 | // Control the fate of second 98 | return new Promise((res, rej) => rej(new Error('example'))); 99 | ``` 100 | Any runtime exceptions in the then callback also result in a rejection of the promise. 101 | 102 | * A quick example would to be to explicitly *throw* an error. 103 | ```js 104 | // Control the fate of second 105 | throw new Error('example'); 106 | ``` 107 | * Another possibility of a runtime exception is programming errors, like using an undeclared variable. 108 | 109 | ```js 110 | // Control the fate of second 111 | foo.bar; 112 | ``` 113 | 114 | ***Delete everything*** 115 | One very useful and fundamental behavior of promises is how rejection is propagated. 116 | 117 | Lets say we have a chain of promises with a few `then`'s followed by a `catch` 118 | 119 | ```js 120 | new Promise((res, rej) => { 121 | res(123); 122 | }) 123 | .then(res => { 124 | console.log(res); 125 | return 456; 126 | }) 127 | .then(res => { 128 | console.log(res); 129 | return 789; 130 | }) 131 | .then(res => { 132 | console.log(res); 133 | }) 134 | .catch(err => { 135 | console.log('ERROR:', err.message); 136 | }); 137 | ``` 138 | ***Run to show 123,456,789*** 139 | A promise rejection at any point in the chain will result in all subsequent `then` handlers to be skipped and execution will jump directly to the catch handler: 140 | 141 | ***Run and show error on each step*** 142 | ```js 143 | new Promise((res, rej) => { 144 | res(123); 145 | }) 146 | .then(res => { 147 | console.log(res); 148 | // foo.bar; 149 | return 456; 150 | }) 151 | .then(res => { 152 | console.log(res); 153 | // foo.bar; 154 | return 789; 155 | }) 156 | .then(res => { 157 | console.log(res); 158 | // foo.bar; 159 | }) 160 | .catch(err => { 161 | console.log('ERROR:', err.message); 162 | }); 163 | ``` 164 | 165 | Of course if there is no error in the preceding chain, the catch handler is never called. 166 | 167 | There is more to promises, but the understanding of these then chains and catch cascading is sufficient for using async / await. 168 | 169 | > NOTE: there is more to promises, but this is more that enough to cover async await. 170 | -------------------------------------------------------------------------------- /02 promise/src/index.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/basarat/typescript-async/28296220151e44bf0fe0780a79fa8c89ed852fca/02 promise/src/index.ts -------------------------------------------------------------------------------- /02 promise/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": [ 4 | "es6", 5 | "dom" 6 | ], 7 | "outDir": "lib" 8 | }, 9 | "include": [ 10 | "src" 11 | ], 12 | "compileOnSave": false 13 | } 14 | -------------------------------------------------------------------------------- /03 async/README.md: -------------------------------------------------------------------------------- 1 | # async functions and the await operator 2 | > async / await should really be thought as a better way to use Promises reliably and safely with less chances of programming errors. 3 | 4 | > This lesson covers the fundamentals of annotating a function as async. An `async` function gets the chance to use the `await` keyword. This lesson covers the usages of these keywords. 5 | 6 | ***Have a demo window open*** 7 | * To make a function `async` all you need to do is prefix it with the async keyword. 8 | * async can be used with simple function, arrow functions, and class methods. 9 | 10 | ```js 11 | async function foo() { 12 | } 13 | 14 | const bar = async () => { 15 | } 16 | 17 | class Baz { 18 | async qux() { 19 | } 20 | } 21 | 22 | ``` 23 | Lets discuss the nature of `async` functions in isolation by focusing in on a simple function. 24 | ***Delete the extra functions*** 25 | 26 | An async function *always* returns a promise. 27 | 28 | ```js 29 | async function foo() { 30 | } 31 | 32 | console.log(foo()); 33 | ``` 34 | ***Show the output of the demo*** 35 | 36 | * The promise resolves to the value that is returned by the function. 37 | * Here the function returns the implicit return of all JavaScript functions *undefined*. 38 | ```js 39 | async function foo() { 40 | } 41 | 42 | foo().then(value => { 43 | console.log(value); 44 | }); 45 | 46 | ``` 47 | ***Show the output of the demo*** 48 | 49 | * If we return a value, the promise will resolve to that value. 50 | ```js 51 | async function foo() { 52 | return 123; 53 | } 54 | 55 | foo().then(value => { 56 | console.log(value); 57 | }); 58 | 59 | ``` 60 | ***Show the output of the demo*** 61 | 62 | TypeScript is smart enough to infer the return type for async functions to be the Promise of the returned values. 63 | ***Show the return type information*** 64 | 65 | ***delete the whole code*** 66 | With the return value of async functions out of the way lets focus in on the body of an async function. 67 | 68 | * We setup nodejs to ignore any unhandled promise rejections to have a clean console. 69 | * Next we setup a few promises to use in our async function. 70 | * We create a variable that is not a promise. 71 | * We create a promise that will resolve, 72 | * We also create a promise that will reject. 73 | 74 | 75 | ```js 76 | process.on('unhandledRejection', () => null); 77 | 78 | const notAPromise = 79 | 123; 80 | const promiseThatWillResolve = 81 | new Promise(res => res(456)); 82 | const promiseThatWillReject = 83 | new Promise((res, rej) => rej(new Error('Hello'))); 84 | 85 | ``` 86 | 87 | async function get access to the `await` operator in their function bodies. The await operator can be applied to any variable. 88 | * If the variable is not a promise the value returned from the await operator is same as the variable. 89 | * If the variable is a promise execution in the function body pauses, till the fate of the promise is 90 | 91 | the behavior will be different depending on the fate of the promise, 92 | * If the promise resolves, the value the await operator is the resolved value of the promise. 93 | * If the variable is a promise that gets rejected, the await operator throws an error in the body of the async function which we can catch with the standard synchronous `try` / `catch` constructs. 94 | 95 | ```js 96 | async function foo() { 97 | const res1 = await notAPromise; 98 | console.log({ forNotAPromise: res1 }); 99 | const res2 = await promiseThatWillResolve; 100 | console.log({ forPromiseThatWillResolve: res2 }); 101 | try { 102 | const res3 = await promiseThatWillReject; 103 | console.log('I will never get called as error is thrown in previous line'); 104 | } 105 | catch (e) { 106 | console.log({ forPromiseThatWillReject: e.message }); 107 | } 108 | } 109 | foo(); 110 | ``` 111 | ***run the code*** 112 | Lets go ahead and call this function to verify that works as explained 113 | * The not a promise variable, just resolves to itself. 114 | * The promise that will resolve, returns its final resolved value 115 | * And the promise that gets rejected, interacts with try / catch as expected. 116 | 117 | If a promise takes some time to settle in its fate, the execution at the await operator pauses till the fate is determined. 118 | * Here we are going to wait for 5 seconds before determining the fate of a local promise. 119 | * And if we go ahead and run this code, you can see that execution pauses for 5 seconds and resumes with logging out `Done waiting`. 120 | ```js 121 | async function foo() { 122 | console.log('Waiting 5 seconds'); 123 | await new Promise(res => setTimeout(res, 5000)); 124 | console.log('Done waiting!'); 125 | } 126 | foo(); 127 | ``` 128 | 129 | ***Select the whole async function*** 130 | Essentially, async/await allows your to write asynchronous code based on promises, in a manner that allows you to reuse your synchronous code writing skills. 131 | -------------------------------------------------------------------------------- /03 async/src/index.ts: -------------------------------------------------------------------------------- 1 | process.on('unhandledRejection', () => null); 2 | 3 | const notAPromise = 456; 4 | const promiseThatWillResolve = new Promise(res => res(123)); 5 | const promiseThatWillReject = new Promise((res, rej) => rej(new Error('Hello'))); 6 | 7 | async function foo() { 8 | const res1 = await notAPromise; 9 | console.log({ forNotAPromise: res1 }); 10 | const res2 = await promiseThatWillResolve; 11 | console.log({ forPromiseThatWillResolve: res2 }); 12 | try { 13 | const res3 = await promiseThatWillReject; 14 | console.log('I will never get called'); 15 | } 16 | catch (e) { 17 | console.log({ forPromiseThatWillReject: e.message }); 18 | } 19 | } 20 | 21 | foo(); 22 | -------------------------------------------------------------------------------- /03 async/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": [ 4 | "es6", 5 | "dom" 6 | ], 7 | "outDir": "lib" 8 | }, 9 | "include": [ 10 | "src" 11 | ], 12 | "compileOnSave": false 13 | } 14 | -------------------------------------------------------------------------------- /04 flow/README.md: -------------------------------------------------------------------------------- 1 | # Parallel and serial execution using async / await 2 | > The great thing about asynchronous programming is that you can do multiple things in parallel. E.g. you can make multiple network requests, or read multiple files from the file system. This lesson covers how to write parallel as well as serial async code. 3 | 4 | ***Have demo window open*** 5 | We start off by bringing in a function `getUserDetails`. 6 | 7 | The implementation of this function is not important beyond the fact that 8 | * it takes a github user handle 9 | * and returns a promise to the details which are resolved asynchronously. 10 | 11 | ```js 12 | import { getUserDetails } from './getUserDetails'; 13 | 14 | ``` 15 | 16 | Now in our main application we have an `async` `main` function that we will execute upfront. 17 | 18 | ```js 19 | async function main() { 20 | 21 | } 22 | 23 | main(); 24 | ``` 25 | 26 | We have a few github user handles that we want to get the details for. 27 | 28 | ```js 29 | const handles = [ 30 | 'basarat', 31 | 'eggheadio', 32 | 'joelhooks' 33 | ]; 34 | ``` 35 | 36 | Getting details for each of these handles one by one is a very easy task with `async`/`await` 37 | * We simply loop through the handles one by one with a simple `forof` loop 38 | * We await the result of each `handle` with `getUserDetails`. 39 | * Once the result comes back, we simply log it out. 40 | 41 | ```js 42 | for (const handle of handles) { 43 | const item = await getUserDetails(handle); 44 | console.log(` 45 | Name: ${item.name} 46 | Location: ${item.location} 47 | `); 48 | } 49 | ``` 50 | 51 | ***Run the demo and show the sequential flow*** 52 | Doing this serial sequence of events is something that is way too easy thanks to async await. 53 | 54 | ***Delete the for loop*** 55 | Sometimes you might want to run a bunch of operations in parallel and wait for all of them to resolve. This can be done with `Promise.all`. 56 | 57 | * We start off by running all the calls to `getUserDetails` in parallel. At this point we have an array of promises that will resolve independently. 58 | * `Promise.all` is a native function that takes an array of promises and returns a new promise that resolves with an array of resolved values for each of the promise. 59 | * Now that we have a single promise we can await it easily giving a single array of resolved values. 60 | * Now we simply loop over the elements of the array and log it out. 61 | 62 | ```js 63 | const allPromises = handles.map(getUserDetails); 64 | const combinedPromise = Promise.all(allPromises); 65 | const details = await combinedPromise; 66 | for (const item of details) { 67 | console.log(` 68 | Name: ${item.name} 69 | Location: ${item.location} 70 | `); 71 | } 72 | ``` 73 | ***Run the demo*** 74 | You can see that we get all the three results at the same time and that the overall process is much faster as we get the details in parallel. 75 | 76 | ***Delete everything starting from `const combinedPromise`*** 77 | One final native control flow worth mentioning is `Promise.race`. 78 | 79 | * This function takes an array of promises just like `Promise.all` and returns a new promise. 80 | * The fate of this new promise is equal to the fate of the first promise that resolves or rejects. 81 | * Here we simply log out the result of the first promise that wins. 82 | 83 | ```js 84 | const resultOfPromiseThatWins = Promise.race(allPromises); 85 | const item = await resultOfPromiseThatWins; 86 | console.log(` 87 | Name: ${item.name} 88 | Location: ${item.location} 89 | `); 90 | ``` 91 | 92 | ***Run the code*** 93 | In our case here the first promise resolves the fastest and hence that is the result of the item. 94 | -------------------------------------------------------------------------------- /04 flow/src/getUserDetails.ts: -------------------------------------------------------------------------------- 1 | const people = { 2 | basarat: { 3 | name: 'Basarat Ali Syed', 4 | location: 'Melbourne, Australia' 5 | }, 6 | eggheadio: { 7 | name: 'egghead.io', 8 | location: 'Recording booth', 9 | }, 10 | joelhooks: { 11 | name: 'Joel Hooks', 12 | location: 'Vancouver, WA' 13 | } 14 | } 15 | 16 | /** 17 | * This is a mocked out version because github API throttling is pretty bad. 18 | * Also the code below means it will continue to work for a long long time (longer than github api 🌹) 19 | * */ 20 | export async function getUserDetails(handle: string) { 21 | return new Promise<{ name: string, location: string }>(res => { 22 | setTimeout(() => { 23 | res(people[handle]); 24 | }, 1000); 25 | }); 26 | } 27 | -------------------------------------------------------------------------------- /04 flow/src/index.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/basarat/typescript-async/28296220151e44bf0fe0780a79fa8c89ed852fca/04 flow/src/index.ts -------------------------------------------------------------------------------- /04 flow/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": [ 4 | "es6", 5 | "dom" 6 | ], 7 | "outDir": "lib" 8 | }, 9 | "include": [ 10 | "src" 11 | ], 12 | "compileOnSave": false 13 | } 14 | -------------------------------------------------------------------------------- /05 forAwaitOf/README.md: -------------------------------------------------------------------------------- 1 | # Asynchronous iteration using for-await-of 2 | > The `for-await-of` syntax is similar to the `for-of` iteration. The key difference is that it automatically awaits any promises generated by the iterator. This lesson covers how to consume async data sources easily with `for-await-of`. 3 | 4 | > `for-await-of` essentially allows you to use `async/await` in a generator function. 5 | 6 | ***Have the demo window open*** 7 | 8 | * Here we have a simple generator function that returns numbers one by one. 9 | * We increment the number and if it becomes more than 10 we stop. 10 | * We can use generator functions in standard synchronous javascript with a simple `main` function 11 | * and we use `forof` to loop through all the items returned by the numbers function. 12 | * Then we log out the number 13 | * Lets invoke the main function and observe its behavior 14 | 15 | ```js 16 | function* numbers() { 17 | let index = 1; 18 | while (true) { 19 | yield index; 20 | index = index + 1; 21 | if (index > 10) { 22 | break; 23 | } 24 | } 25 | } 26 | 27 | function main() { 28 | for (const num of numbers()) { 29 | console.log(num); 30 | } 31 | } 32 | main(); 33 | 34 | ``` 35 | 36 | ***Run the code*** 37 | You can see that it behaves as expected logging out `10` numbers. 38 | 39 | 40 | ***Delete the main function to prevent infinity loop*** 41 | Now lets imagine that we are going to get the next number from an external source like a backend service that will perform its magic to increment the index. 42 | 43 | ```js 44 | import { magic } from './server'; // NEW LINE 45 | 46 | function* numbers() { 47 | let index = 1; 48 | while (true) { 49 | yield index; 50 | index = magic(index); // REPLACE LINE, Show error 51 | if (index > 10) { 52 | break; 53 | } 54 | } 55 | } 56 | ``` 57 | 58 | ***however info on magic(index)*** 59 | * Here we have a type mismatch. 60 | * We have a promise to a number and we would really like to have the resolved `number` to make our decision for the loop termination. 61 | 62 | 63 | This can be done easily with, (you guessed it) async await. 64 | 65 | ```js 66 | import { magic } from './server'; 67 | 68 | async function* numbers() { // ADD ASYNC 69 | let index = 1; 70 | while (true) { 71 | yield index; 72 | index = await magic(index); // ADD AWAIT 73 | if (index > 10) { 74 | break; 75 | } 76 | } 77 | } 78 | 79 | ``` 80 | ***select async function*** 81 | Before the `for await of` JavaScript feature, a generator function could not be async. This new feature requires a runtime polyfill to work correctly called the `asyncIterator` symbol. 82 | 83 | We can provide it easily here, alternatively you can use a library like core-js that will polyfill it for you. 84 | 85 | ```js 86 | (Symbol as any).asyncIterator = 87 | (Symbol as any).asyncIterator 88 | || Symbol.for("Symbol.asyncIterator"); 89 | ``` 90 | 91 | * This `numbers` function is an async generator and returns an async iterator. Similar to how we use `for of` loops with synchronous iterators, we can use `for await of` loops with async iterators. 92 | 93 | ```js 94 | async function main() { 95 | for await (const num of numbers()) { 96 | console.log(num); 97 | } 98 | } 99 | main(); 100 | ``` 101 | ***Run the code*** 102 | You can see the for await of loop works as expected, getting a number asynchronously and logging it out. 103 | 104 | ***Select the `async` in `numbers`, `await` in `number`, for await in `main`*** 105 | To summarize, when you want to use `async await` in generators, you can use `for await of` to iterate its results. 106 | -------------------------------------------------------------------------------- /05 forAwaitOf/src/index.ts: -------------------------------------------------------------------------------- 1 | import { magic } from './server'; 2 | 3 | (Symbol as any).asyncIterator = 4 | (Symbol as any).asyncIterator 5 | || Symbol.for("Symbol.asyncIterator"); 6 | 7 | async function* numbers() { 8 | let index = 1; 9 | while (true) { 10 | yield index; 11 | index = await magic(index); 12 | if (index > 10) { 13 | break; 14 | } 15 | } 16 | } 17 | 18 | async function main() { 19 | for await (const num of numbers()) { 20 | console.log(num); 21 | } 22 | } 23 | main(); 24 | -------------------------------------------------------------------------------- /05 forAwaitOf/src/server.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Returns the next number after a delay 3 | * 4 | * The objective is to simply demonstrate that you might want to observe 5 | * the value of a promise before determining if you should yield 6 | **/ 7 | export function magic(num: number) { 8 | return new Promise(res => { 9 | setTimeout(() => res(num + 1), 1000); 10 | }); 11 | } -------------------------------------------------------------------------------- /05 forAwaitOf/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "lib": [ 5 | "es2017", 6 | "dom", 7 | "esnext.asynciterable" 8 | ], 9 | "outDir": "lib" 10 | }, 11 | "include": [ 12 | "src" 13 | ], 14 | "compileOnSave": false 15 | } 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `async`/`await` using TypeScript 2 | 3 | Docs / Code to an accompanying video course on async/await with TypeScript. 4 | 5 | # Setup 6 | ``` 7 | npm install 8 | ``` 9 | 10 | ## Lessons 11 | 12 | * [Simplify callbacks with async await](https://egghead.io/lessons/typescript-simplify-asynchronous-callback-functions-using-async-await) 13 | * [02 Promise](https://egghead.io/lessons/promise-fundamentals-using-typescript) 14 | * [03 Async Await](https://egghead.io/lessons/typescript-async-functions-and-the-await-operator) 15 | * [04 Serial / Parallel / Race execution, Control flow](https://egghead.io/lessons/egghead-parallel-and-serial-execution-using-async-await) 16 | * [05 Asynchronous iteration using for-await-of](https://egghead.io/lessons/javascript-asynchronous-iteration-using-for-await-of) 17 | 18 | 19 | ## Future 20 | 21 | ### Why use TypeScript quiz: 22 | 23 | What does this function return? 24 | 25 | async function foo() { 26 | return 123; 27 | } 28 | 29 | TypeScript knows :) 30 | 31 | What does this function return: 32 | 33 | declare function backend(): Promise<{key: string}>; 34 | async function foo() { 35 | return backend() 36 | .catch(err => { 37 | console.log('Backend failure:', err); 38 | }); 39 | } 40 | 41 | I see this code out in the wild all the time. 42 | 43 | Hopefully you can see that even for really simple codebases, when dealing with async await and promises, it is great to have TypeScript on your side. 44 | 45 | ### utils.promisify 46 | Worth mentioning. 47 | -------------------------------------------------------------------------------- /cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/basarat/typescript-async/28296220151e44bf0fe0780a79fa8c89ed852fca/cover.png -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typescript-async", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@types/node": { 8 | "version": "8.0.53", 9 | "resolved": "https://registry.npmjs.org/@types/node/-/node-8.0.53.tgz", 10 | "integrity": "sha512-54Dm6NwYeiSQmRB1BLXKr5GELi0wFapR1npi8bnZhEcu84d/yQKqnwwXQ56hZ0RUbTG6L5nqDZaN3dgByQXQRQ==" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typescript-async", 3 | "version": "1.0.0", 4 | "description": "Docs / Code to an accompanying video course on async/await with TypeScript.", 5 | "main": "index.js", 6 | "dependencies": { 7 | "@types/node": "8.0.53" 8 | }, 9 | "devDependencies": {}, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/basarat/typescript-async.git" 16 | }, 17 | "keywords": [], 18 | "author": "", 19 | "license": "ISC", 20 | "bugs": { 21 | "url": "https://github.com/basarat/typescript-async/issues" 22 | }, 23 | "homepage": "https://github.com/basarat/typescript-async#readme" 24 | } 25 | --------------------------------------------------------------------------------