KEMBAR78
Understanding Async/Await in Javascript | PPTX
Understanding
async/await
in Javascript
Hao Luo
Sr Technical Evangelist
Microsoft
@howlowck
About Me
Overview
• Single-Threaded
• Callbacks
• Promises
• Generators
• Async/Await
Heads Up
• No ES6 syntactic sugar
• Trivial Demos
• setTimeout or simple APIs
• Perfect World (no errors)
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.
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
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
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
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.
http://bit.ly/eventloop-explained
Philip Roberts
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
Async Impact
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)
}
Promises
• 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)
})
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
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
Generators
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
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
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
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
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
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)
}
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
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
})
}
Closing Thoughts
• Understand the basics by looking behind the curtain
• Resist the urge to rage quit
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

Understanding Async/Await in Javascript

  • 1.
    Understanding async/await in Javascript Hao Luo SrTechnical Evangelist Microsoft @howlowck
  • 2.
  • 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)
  • 5.
    NodeJS http://bit.ly/original-nodejs http://bit.ly/original-nodejs-slides We’re taught I/Owith 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.
  • 6.
    Callbacks Ryan’s Example: puts("Enter yourname: "); 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
  • 7.
    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
  • 8.
    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
  • 9.
    Phew… That wasa 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.
  • 10.
  • 11.
    Callback Hell Ryan’s Example: puts("Enteryour 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
  • 12.
  • 13.
    ES2016 async/await puts('Enter yourname: ') 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) }
  • 14.
  • 15.
    • A Promiseis 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) })
  • 16.
    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
  • 17.
    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
  • 18.
  • 19.
    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
  • 20.
    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
  • 21.
    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
  • 22.
    Generators + Promises functionrequestName () { 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
  • 23.
    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
  • 24.
    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) }
  • 25.
    Async/await vs Generator+Promises asyncfunction 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
  • 26.
    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 }) }
  • 27.
    Closing Thoughts • Understandthe basics by looking behind the curtain • Resist the urge to rage quit
  • 28.
    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