Asynchronous Behavior
Part 2
Review
By default, JavaScript has a synchronous and single threaded execution model
Review
Changes to the DOM or style will not be rendered until JavaScript execution halts
const bar = document.querySelector('#bar');
for(let i = 0; i < 100; i += 1){
bar.style.width = `${i}%`;
}
Review
For certain events, or functions, JavaScript can execute code asynchronously
- Network Requests
- (fetch)
- User Input
- (keypress, mouse press)
- Timers
- (setInterval, setTimeout)
- WebWorkers
Two methods
of accomplishing asynchronous behavior
Callbacks
Promises
Callbacks
A callback is a function passed to another function as a parameter
The function can be executed (called) when some work or event is complete
const DoSomethingWithPi = callback => {
const pi = reallyLongFunction();
callback(pi)
};
const DoubleAndLog = data => console.log(data*2);
DoSomethingWithPi(DoubleAndLog);
//6.2831853072
Callback Example
(Named function)
const DoSomethingWithPi = callback => {
const pi = reallyLongFunction();
callback(pi)
};
DoSomethingWithPi(data => console.log(data*2));
//6.2831853072
Inline callback
(Anonymous Function)
codepen example
demo basic callback, event binding, timer
//Event Listener
const name = document.querySelector('#name');
name.addEventListener('keydown', event => {
console.log(event.keycode);
});
//setTimeout
window.setTimeout(()=>{
alert('5 seconds went by!')
}, 5000);
Document and Window functions implement USING callback pattern
const img = document.querySelector('#img');
const showPopup = () => {
//show a popup window
document.addEventListener('click', hidePopup);
};
const hidePopup = () => {
//hide the popup window
document.removeEventListener('click', hidePopup);
};
img.addEventListener('click', showPopup);
Benefits of NAMED callbacks
Multiple Async Processes
A user clicks 'login,' which triggers a network request to the login service. This returns a session, which now requests the users personalized content. The content is sent to a render function.
Multiple Async Processes
userButtonClick(
LoginService(
GetPersonalizedData(
RenderContent(){
//do work here
})
})
})
});
Callback Hell
fs.readdir(source, function (err, files) {
if (err) {
console.log('Error finding files: ' + err)
} else {
files.forEach(function (filename, fileIndex) {
console.log(filename)
gm(source + filename).size(function (err, values) {
if (err) {
console.log('Error identifying file size: ' + err)
} else {
console.log(filename + ' : ' + values)
aspect = (values.width / values.height)
widths.forEach(function (width, widthIndex) {
height = Math.round(width / aspect)
console.log('resizing ' + filename + 'to ' + height + 'x' + height)
this.resize(width, height).write(dest + 'w' + width + '_' + filename, function(err) {
if (err) console.log('Error writing file: ' + err)
})
}.bind(this))
}
})
})
}
})
When your code starts to resemble a pyramid, you're in callback hell.
Promises
What is a promise?
A Promise is a proxy for a value not necessarily known when the promise is created. It allows you to associate handlers with an asynchronous action's eventual success value or failure reason. This lets asynchronous methods return values like synchronous methods: instead of immediately returning the final value, the asynchronous method returns a promise to supply the value at some point in the future.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
What does a promise look like?
const dice = new Promise( ... );
dice.then( res => {})
.then( res => {})
.catch( res => {});
Look familiar?
const dice = new Promise( ... );
dice.then( res => {})
.then( res => {})
.catch( res => {});
fetch('http://www.domain.com/api/v1/service')
.then( res => {})
.then( res => {})
.catch( err => {});
Just like addEventListener is implemented using a callback, fetch is implemented using a promise
Interior of a Promise
A new promise takes a function (which does something asynchronous). This function has two parameters: resolve and reject.
Resolve triggers the first "then"
Reject triggers the "catch"
Promise Example
const RiggedDice = new Promise((resolve, reject) => {
const roll = Math.floor(Math.random() * 5) + 1;
if(roll >= 5){
resolve(roll);
} else {
reject(roll);
}
});
RiggedDice
.then(roll => console.log(`Yay! you rolled a ${roll}`)
.catch(roll => console.log(`Bummer! you rolled a ${roll}`);
codepen example
Promise based image loader
Asynchronous Behavior 2
By Michael Jasper
Asynchronous Behavior 2
- 602