I promise to get to Promises, but first...
Let's say we are running some potentially very time intensive tasks, and because we don't want to just pause our program the moment the interpreter starts to do said task, we need to find a way to have a function that performs an operation and still allows the program to run. This is essentially what callback functions do.
When a function is passed into another function, its resolved value can essentially be stored within that function and then accessed when the outer function is called.
For example, if we wanted to describe a round of duck-duck-goose, we could do it using callbacks:
//we define two functions that take callback function parameters
function duck(cbFunc){
let duck = "...duck..."
//and invoke those callbacks on some value
cbFunc(duck)
}
function goose(cbFunc){
let goose = "...goose!"
cbFunc(goose)
}
//now we write a function to play duck-duck-goose
function playDDG(){
//we call duck passing in a function that...
duck(person1 => {
//...logs the input of the passed-in function...
console.log(person1)
//...and calls duck passing in a function that...
duck(person2 => {
//...logs the input of the passed-in function...
console.log(person2)
//...and calls goose passing in a function that...
goose(person3 =>{
//...logs the input of the passed-in function.
console.log(person3)
})
})
})
}
console.log(playDDG())
While this is an effective work-around to the issue of storing a resolved value until it is needed, the syntax of the nested functions can quickly blossom out of the bounds of readability.
This is where I fulfill my earlier promise.
The Promise object represents the eventual completion (or failure) of an asynchronous operation and its resulting value (MDN).
While difficult to state it more eloquently than the official documentation, we can maybe say some things in that are true about them to construct a more comprehensive understanding.
Promises are objects, proxies for another value that is not yet accessible by the program
Promise objects are created and given asynchronous code to execute.
New Promise objects take in up to two parameters:
A callback function for a fulfilled promise.
A callback function fora Rejected promise.
Promises have one of three states:
- Pending, not resolved or rejected
- Fulfilled, the promise has been resolved
- Rejected, the promise has been rejected :-(
Promises are used as an alternative to callbacks because they can be chained.
Because it is an object, it has some methods. One of which is. then().
Let's say we have a Promise object:
//it takes a resolve callback and a reject callback
let mathPromise = new Promise((resolve, reject) =>{
//we do some operation inside
let three = 3;
let four = 4;
if (three + four === 7){
//if we have met the criteria, we resolve
resolve(`Yes it is ${three + four}`)
} else {
//if not we reject
reject("...no")
}})
The .then() method tells us what to do next should the promise be returned resolved. It's basement-dwelling fish-mutant sibling is the .catch() method, to catch that something has gone wrong somewhere and throw an error.
//if mathPromise returns resolved, then
mathPromise.then((thenFuncVal) => {
//log the value of the successful resolve
console.log(thenFuncVal)
}).catch((catchFuncVal)=>{
console.log(catchFuncVal)
})
Callbacks are stored in the object .then() is called on and a new promise object is returned, thus these method invocations are chainable.
//we make a new promise
let wordPromise = new Promise((resolve, reject)=>{
let word1 = "hello"
let word2 = "HELLO"
if (word1 === word2.toLowerCase()){
resolve("I heard you the first time")
} else {
reject("WHAT?")
}
})
//we verify our mathPromise
mathPromise.then((thenFuncVal) => {
console.log(thenFuncVal)
//and if it resolves, we return our wordPromise object
return wordPromise
})
//and then we verify that returned wordPromise
.then((thenFuncVal) => {
console.log(thenFuncVal)
})
//and if anything gets rejected, we make sure to indicate that rejection
.catch((catchFuncVal)=>{
console.log(catchFuncVal)
})
If we changed a value say in mathPromise such that it was rejected, we would log the value in the reject portion of that conditional, but also we would no longer evaluate wordPromise.
While this aims only to describe the mechanical operation of promise objects, their use in asynchronous programming is indispensable. They preserve the functionality of using callbacks while being able to use object method syntax.
Top comments (0)