Part 2
By default, JavaScript has a synchronous and single threaded execution model
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}%`;
}
For certain events, or functions, JavaScript can execute code asynchronously
of accomplishing asynchronous behavior
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)
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
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.
userButtonClick(
LoginService(
GetPersonalizedData(
RenderContent(){
//do work here
})
})
})
});
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.
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
const dice = new Promise( ... );
dice.then( res => {})
.then( res => {})
.catch( res => {});
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
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"
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}`);
Promise based image loader