Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Understanding Async/Await in Javascript

175 views

Published on

Javascript traditionally relied on callback functions to handle asynchronous processes. As your Javascript application grows, you would encounter “Callback Hell”, which makes your code unreadable and application error-prone. There are now several ways to combat callback hell, and make your application development experience more enjoyable.

The presentation will quickly go over the shortcomings of callback functions. It will also provide a thorough walk-through of Promises, and Generators, and combine the two paradigms to explain the new ES2016 feature async/await.

Published in: Technology
  • Be the first to comment

  • Be the first to like this

Understanding Async/Await in Javascript

  1. 1. Understanding async/await in Javascript Hao Luo Sr Technical Evangelist Microsoft @howlowck
  2. 2. About Me
  3. 3. Overview • Single-Threaded • Callbacks • Promises • Generators • Async/Await Heads Up • No ES6 syntactic sugar • Trivial Demos • setTimeout or simple APIs • Perfect World (no errors)
  4. 4. NodeJS http://bit.ly/original-nodejs http://bit.ly/original-nodejs-slides We’re taught I/O with this: puts("Enter your name: "); var name = gets(); puts("Name: " + name); We’re taught to demand input and do nothing until we have it. Code like puts("Enter your name: "); gets(function (name) { puts("Name: " + name); }); is rejected as too complicated.
  5. 5. Callbacks Ryan’s Example: puts("Enter your name: "); gets(function (name) { puts("Name: " + name); }); var form = document.querySelector('#login') form.addEventListener('submit', function () { doSomething() doSomethingElse() }) http://bit.ly/explaining-async 01 ✔️7.6+ ✔️8.0.* ❌8.1.0 ❌8.1.1 ✔️8.1.2
  6. 6. Call Stack console.log(getAnswer(3)) getAnswer(3) inWords(4) function inWords (answer) { return 'The Answer is ' + answer } function getAnswer (num) { return inWords(num + 1) } let input = 3 console.log(getAnswer(input)) main() Run to completion
  7. 7. pretendToThink(input) setTimeout(cb)getAnswer(3)console.log('thinking...') inWords(4) function inWords (answer) { return 'The Answer is ' + answer } function getAnswer (num) { return inWords(num + 1) } function pretendToThink (num) { setTimeout(function cb () { console.log(getAnswer(num)) }, 8000) console.log('thinking...') } let input = 3 pretendToThink(input) Call Stack Web API / Node C++ main() cb Callback Queue console.log(getAnswer(3)) cb() cb Event Loop Concurrency
  8. 8. Phew… That was a lot… • When we talk about Single-Threaded, it means there is only one call stack and one event loop. • Event Loop watches the callback queue and the call stack • If the call stack is empty, and there is something in the callback queue, the Event Loop puts the callback function in the call stack.
  9. 9. http://bit.ly/eventloop-explained Philip Roberts
  10. 10. Callback Hell Ryan’s Example: puts("Enter your name: "); gets(function (name) { puts("Name: " + name); }); Ryan’s Extended Example: puts('Enter your name: ') gets(function (name) { puts('Name: ' + name) puts('Enter your email: ') gets(function (email) { puts('Email: ' + name) puts('Enter your phone number: ') gets(function (phone) { puts('Phone: ' + phone) puts('Enter your birth date: ') gets(function (birthDate) { puts('Birth Date: ' + birthDate) }) }) }) }) 02
  11. 11. Async Impact
  12. 12. ES2016 async/await puts('Enter your name: ') gets(function (name) { puts('Name: ' + name) puts('Enter your email: ') gets(function (email) { puts('Email: ' + name) puts('Enter your phone number: ') gets(function (phone) { puts('Phone: ' + phone) puts('Enter your birth date: ') gets(function (birthDate) { puts('Birth Date: ' + birthDate) }) }) }) }) async function program () { puts('Enter your name: ') var name = await gets() puts('Name: ' + name) puts('Enter your Email: ') var email = await gets() puts('Email: ' + email) puts('Enter your Phone: ') var phone = await gets() puts('Phone: ' + phone) puts('Enter your Birth Date: ') var date = await gets() puts('Date: ' + date) }
  13. 13. Promises
  14. 14. • A Promise is a value that guarantees a future value. • In Javascript ES6, a Promise is an object that has a then method on it. • When instantiating a Promise Object, it takes in a function that has two callback parameters (commonly known as resolve, and reject) Promises Overview var requestName = new Promise(function (resolve) { puts('Enter Your Name: ') gets(function (name) { resolve(name) }) }) requestName.then(function (name) { console.log(name) })
  15. 15. var requestName = new Promise(function (resolve) { puts('Enter Your Name: ') gets(function (name) { resolve(name) }) }) requestName.then(function (name) { console.log(name) }) The then method • The then method always returns a Promise • The then method takes in two functions as parameters • The first function is the resolve function
  16. 16. function requestName () { return new Promise(function (resolve) { puts('Enter Your Name: ') gets(function (name) { resolve(name) }) }) } function requestEmail () { return new Promise(function (resolve) { puts('Enter Your Email: ') gets(function (email) { resolve(email) }) }) } … … puts('Enter your name: ') gets(function (name) { puts('Name: ' + name) puts('Enter your email: ') gets(function (email) { puts('Email: ' + name) puts('Enter your phone number: ') gets(function (phone) { puts('Phone: ' + phone) puts('Enter your birth date: ') gets(function (birthDate) { puts('Birth Date: ' + birthDate) }) }) }) }) requestName() .then(function (name) { puts('Name: ' + name) }) .then(requestEmail) .then(function (email) { puts('Email: ' + email) }) .then(requestPhone) .then(function (phone) { puts('Phone: ' + phone) }) .then(requestBirthDate) .then(function (birthDate) { puts('Birth Date: ' + birthDate) }) Extended Example 03
  17. 17. Generators
  18. 18. Generator Function • function * and yield • A generator function returns an iterator object • an iterator object has a next method on it. • The next method runs/continues the generator function up to yield • The next method returns an object that has two parameters value and done
  19. 19. function * countDown () { puts('Fuel Check') yield 3 puts('Engine Check') yield 2 puts('Electrical Check') yield 1 puts('Launching...') } Generator Scope Iterator Scope var iterator = countDown() var yieldedResult = iterator.next() puts(yieldedResult.value) yieldedResult = iterator.next() puts(yieldedResult.value) yieldedResult = iterator.next() puts(yieldedResult.value) yieldedResult = iterator.next() puts(yieldedResult.value) Basic Example // object that has a next method on it // { value: 3, done: false } // { value: 2, done: false } // { value: 1, done: false } // { value: undefined, done: true } • function * and yield • A generator function returns an iterator object • an iterator object has a next method on it. • The next method runs/continues the generator function up to yield • The next method returns an object with two params value and done 04
  20. 20. Special Yield function * countDown () { puts('Fuel Check') yield 3 puts('Engine Check') yield 2 puts('Electrical Check') yield 1 puts('Launching...') } Generator Scope Iterator Scope var iterator = countDown() var yieldedResult = iterator.next() puts(yieldedResult.value) yieldedResult = iterator.next() puts(yieldedResult.value) yieldedResult = iterator.next() puts(yieldedResult.value) yieldedResult = iterator.next() puts(yieldedResult.value) var engineStatus = yield 3yield 3 // { value: 3, done: false } var engineCheck = {everythingGood: true} yieldedResult = iterator.next(engineCheck) // {everythingGood: true} • The yield keyword can produce a value • The value is passed in by the following next method call 05
  21. 21. Generators + Promises function requestName () { return new Promise(function (resolve) { callbackGets(function (name) { resolve(name) }) }) } function * program () { puts('Enter Your Name: ') var name = yield requestName() puts('Name: ' + name) puts('Enter Your Email: ') var email = yield requestEmail() puts('Email: ' + email) puts('Enter Your Phone: ') var phone = yield requestPhone() puts('Phone' + phone) puts('Enter Your Birth Date: ') var date = yield requestBirthDate() puts('Birth Date' + date) } var running = program() running.next() .value .then(function (name) { running.next(name) .value .then(function (email) { running.next(email) .value .then(function (phone) { running.next(phone) .value .then(function (birthDate) { running.next(birthDate) }) }) }) }) function requestEmail () { return new Promise(function (resolve) { callbackGets(function (email) { resolve(email) }) }) } function requestPhone () { return new Promise(function (resolve) { callbackGets(function (phone) { resolve(phone) }) }) } function requestBirthDate () { return new Promise(function (resolve) { callbackGets(function (birthDate) { resolve(birthDate) }) }) } // iterator object // {done: false, value: Promise} // Promise (has a then method) // then takes the callback // {done: false, value: Promise} // Promise (has a then method) 06
  22. 22. function requestBirthDate () { return new Promise(function (resolve) { callbackGets(function (birthDate) { resolve(birthDate) }) }) } function requestPhone () { return new Promise(function (resolve) { callbackGets(function (phone) { resolve(phone) }) }) } function requestEmail () { return new Promise(function (resolve) { callbackGets(function (email) { resolve(email) }) }) } function requestName () { return new Promise(function (resolve) { callbackGets(function (name) { resolve(name) }) }) } data data data data data Refactoring Promises name name email email phone phone birthDate birthDate data data data function gets () { return new Promise(function (resolve, reject) { callbackGets(function (data) { resolve(data) }) }) } 07
  23. 23. Refactoring Runner var running = program() running.next() .value .then(function (name) { running.next(name) .value .then(function (email) { running.next(email) .value .then(function (phone) { running.next(phone) .value .then(function (birthDate) { running.next(birthDate) }) }) }) }) // iterator object // {done: false, value: Promise} // Promise (has a then method) // then takes the callback // {done: false, value: Promise} // Promise (has a then method) function run (generatorFunc) { } run(program) 07 var iterator = generatorFunc() // iterator object var yieldedObject // undefined-> name -> email -> phone -> birthDate function loop (resolvedValue) { } loop() // start the loop yieldedObject = iterator.next(resolvedValue) // yieldObject == {done: false, value: Promise} if (!yieldedObject.done) { yieldedObject.value.then(loop) }
  24. 24. Async/await vs Generator+Promises async function program () { puts('Enter your name: ') var name = await gets() puts('Name: ' + name) puts('Enter your Email: ') var email = await gets() puts('Email: ' + email) puts('Enter your Phone: ') var phone = await gets() puts('Phone: ' + phone) puts('Enter your Birth Date: ') var date = await gets() puts('Date: ' + date) } function * program () { puts('Enter your Name: ') var name = yield gets() puts('Name: ' + name) puts('Enter your Email: ') var email = yield gets() puts('Email: ' + email) puts('Enter your Phone: ') var phone = yield gets() puts('Phone: ' + phone) puts('Enter your Birth Date: ') var date = yield gets() puts('Birth Date: ' + date) } 07 10
  25. 25. Fetch API Example function * program () { puts('Enter your name: ‘) var name = yield requestName() puts('Fetch from Server...’) var burgerName = yield fetchRandomBurgerName() puts(name + ' wants a ' + burgerName) } runs(program) var runs = require('./lib/runs') var fetch = require('node-fetch') var gets = require('./lib/gets') var puts = require('./lib/puts') var apiRoute = 'https://bobsburger-names.azurewebsites.net/api/random' function requestName () { return new Promise(gets) } function fetchRandomBurgerName () { return fetch(apiRoute) .then(function (res) { return res.json() }) .then(function (data) { return data.name }) }
  26. 26. Closing Thoughts • Understand the basics by looking behind the curtain • Resist the urge to rage quit
  27. 27. Resources & Questions? • http://bit.ly/original-nodejs • http://bit.ly/original-nodejs-slides • http://bit.ly/eventloop-explained • https://davidwalsh.name/es6-generators • https://github.com/howlowck/explaining-async @HowLowCK

×