the evolution of java script asynchronous calls
TRANSCRIPT
The Evolution of JavaScript Asynchronous Calls
Pham Huy Hoang - Harry PhamGithub: conanak99
Agenda
How we deal with asynchronous call in JS
1. Innocent Callback and callback hell2. Promise all the things3. The magic of async/await
JS is single-threaded ● JS has a single Call Stack => Can only do one thing at a time.● While the Call Stack has functions to execute, the browser can’t actually
do anything else => Browser hang and laggy UI● Solution: Asynchronous Call
This demo will hang the browser
1. The innocent Callback
● Functions are first-class objects● We can pass a function as an argument in another function ● Later execute that passed-in function at convenience time
jQuery callback style
$(document).ready(function() {
$('#button').on('click', function(event) {
$.getJSON('/data.json', function(data) {
console.log(data);
});
});
});
Demo: https://codepen.io/huyhoangpham/pen/veGYrw?editors=1010#0
Callback hellsgetData(function(a) {
getMoreData(function(b) {
getMoreData(function(c) {
getMoreData(function(d) {
getMoreData(function(e) {
// do something
});
});
});
});
})
https://codepen.io/huyhoangpham/pen/VMaYwo?editors=1010
The downside
● Make code difficult to maintain and debug● Exception handling is … tedious● Anonymous inline function = hard-to-read call stack
2. Promise all the things
● Represents the eventual result of an asynchronous operation. ● Must be in one of three states: pending, fulfilled, or rejected.
Resolve and reject
const promise = new Promise((resolve, reject) => {
// do async stuff
resolve('DONE!');
});
promise.then((result) => {
console.log(result); // result will be 'DONE!'
});
Demo:
https://codepen.io/huyhoangpham/pen/gGrbMM?editors=1010
const promise = new Promise((resolve, reject) =>
{
// do async stuff
reject(new Error('FAIL!'));
});
promise
.then((result) => {
// Will not be called
})
.catch((error) => {
console.log(error); // FAIL!
})
Chaining promisesfunction getData(input) {
return Promise.resolve(input + ' data');
}
getData('hello')
.then((result) => {
return result + ' chain promise';
// result: 'hello data'
})
.then((result2) => {
console.log(result2);
// result2: 'hello data chain promise'
})
Demo: https://codepen.io/huyhoangpham/pen/GMZgrq?editors=1010
getData('hello')
.then((result) => {
throw new Error('Oops');
})
.then((result2) => {
return result2;
})
.then((result3) => {
return result3;
})
.catch((error) => {
console.log(error); //oops
})
How promise solve callback hell
getData(function(a) {
getMoreData(function(b) {
getMoreData(function(c) {
getMoreData(function(d) {
getMoreData(function(e) {
// do something
});
});
});
});
})
getData()
.then(getMoreData)
.then(getMoreData)
.then(getMoreData)
.then(getMoreData)
.then((result) => {
// do something
})
.catch((error) => {
handleError(error);
});
So you want parallel call?Promise.all([
firstAsyncCall(),
secondAsyncCall(),
lastAsyncCall(),
])
.then(result => {
firstAsyncCallResult = result[0];
secondAsyncCallResult = result[1];
lastAsyncCallResult = result[2];
});
Demo: https://codepen.io/huyhoangpham/pen/YrqPVy?editors=1010
Pitfall (Promise hell and error handling)
getData.then(() => {
getMoreData.then(()=> {
getMoreDate.then(() => {
// Do something
});
});
});
promise.then(resolve, reject);
promise.then(
(result) => {
// Do something
throw new Error('This error will not be
caught');
},
(error) => {
console.log(error);
});
Why promise
● Cleaner method signatures -> Easier to read
● Easier to write function and test -> Reduce
cost of maintenance● It allows for chaining of promises -> Clear
and shorter code
Let’s rest for 20 seconds
The magic of async/await (ES7)
Treat functions returning Promise objects as if
they were synchronous
$('#request').click(async () => {
const imgUrl = await findRandomImgPromise('cat');
$('#cat').attr('src', imgUrl);
});
https://codepen.io/huyhoangpham/pen/aLNzLr?editors=1010
Make asynchronous code easy again
getData(function(a) {
getMoreData(function(b) {
getMoreData(function(c) {
getMoreData(function(d) {
getMoreData(function(e) {
// do something
});
});
});
});
})
async function doGreatThing() {
try {
const firstData = await getData();
const secondData = await getMoreData(firstData);
const thirdData = await getMoreDate(secondData);
// How about parallel call?
const saveResults = await Promise.all([
saveData(firstData),
saveData(secondData),
saveData(thirdData)]);
} catch (error) {
console.log(error);
}
}
Magic time, oops… demo time
● Sequential: https://codepen.io/huyhoangpham/pen/VMaYxe?editors=1010● Parellel: https://codepen.io/huyhoangpham/pen/JrXdXK?editors=1010● Looping: https://codepen.io/huyhoangpham/pen/rGeaXX?editors=1010
Everything look … synchronous
● Await keyword is only available in a async function● No more callback, then, or catch => Cleaner code● Easier to debug● Easy looping and error try/catch
=> Everything look … synchronous
How about old browsers?
● Use babel transpiler● Behind the scene: ● Generate a state machine
Looking back
We have came a long way
● From Callback to Promise(ES6) to Async/Await(ES7)
● Callback is still used for event, but should not for
asynchronous call
● Should have a good understanding on Promise
● Use async/await if possible. It makes our life better
JS Code Combo
1. Use bluebird to turn callback into promise
2. Use the magic of async/await
Thank you for listening!