# Promises
# Promises 101
What comes to your mind when i said promise ?
a declaration or assurance that one will do something or that a particular thing will happen
That's is exactly what is it, but with logic. And the best way to represent that it's with objects.
So, in javascript a Promise
is an object representing the eventual completion or failure of an asynchronous (let's see what it exactly means after) operation.
# What it's their purpose?
The idea behind a promise it's make a async lenguaje like javascript capable to create part of the code that can happen sync. In other word, you can spect that certain part of your code will happen in the order that you expect. Because yes, javascript it's not sync like the other language where you type something in order and the code it's executed in that order. Before the introduction to promises in javascript exist a workaround to make code be executed in a sync ways, and that workaround it's use callbacks. But this create another issue with code less legible.
For example if you have the next code:
console.log('1')
console.log('2')
console.log('3')
The output for that will be 1 2 3
always. But when you have a little more async code, like this
console.log('1')
setTimeout(afterTwoSeconds = () => {
console.log('2')
}, 2000)
console.log('3')
This will output 1 3 2
because the code inside the timeout will "wait" 2 second to be executed.
Now you are wonder "Why i would do this? Why i would wait for something in purpose?". Glad to ask. This behavior it's totally normal when you want to fetch something throw your API or any other server, or when you need to fetch some images o something else.
# How to create and use a Promise
Like already talk about, before promises you had some workaround to make some async call, the most common it's use jquery to make some call, but you can make a call with code something like this
function callAjax(url, callback){
var xmlhttp;
// compatible with IE7+, Firefox, Chrome, Opera, Safari
xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function(){
if (xmlhttp.readyState == 4 && xmlhttp.status == 200){
callback(xmlhttp.responseText);
}
}
xmlhttp.open("GET", url, true);
xmlhttp.send();
}
Pretty ugly rigth?
There you had 2 params to the function. The actual URL where to make the call, and the callback, in this case that must be a the function that will be executed when the xmlhttp
status it's 200
and readyState
4
Gladly it's pretty unusual that you had to write code like this, because promises. So if you want to make a request like the code before, now you had a promise call fetch
where the code that you read before can be something like this
fetch(url)
.then(response => console.log(response));
Wait, what it's that then? No worries, i will explain it. But before we need to know how to write a promise.
A promise receive as params a function with two function (yep, javascript), the first argument function will be executed when the promise it's fulfilled (the operation was completed successfully), and the second argument function will be executed when the promise it's rejected (the operation failed)
const promise = new Promise(function(resolve, reject) {
// do a thing, or many things, or two, maybe three
if (/* everything turned out fine */) {
resolve("Stuff worked!");
}
else {
reject(Error("It broke"));
}
});
So, you already know what happen when a promise is resolved, and rejected, but meanwhile the promise return other status pending who it their initial state until a resolve or reject happen.
If we go back to our example with the timeout, with a promise we make that the code print 1 2 3
in order, even if we set the timeout inside.
In order to this we create a function
const timePromise = new Promise((resolve, reject) => {
setTimeout(afterTwoSeconds = () => {
resolve('2');
}, 2000)
})
const inOrderPrint = () => {
console.log('1');
timePromise
.then(resolveResponse => console.log(resolveResponse))
.then(() => console.log('3'));
}
Here we wrap the setTimeout function in a promise that execute the code, once it's fulfilled (the 2000ms time pass) this will be resolved.
What about those then? it's call promise chaining, and this it's executed in order.
So in the execution of the timePromise()
we will print 1
, execute the promise; when it's resolved, we return the value, and the first then captured and pass as first argument, and it's printed, then
(after the first then) we executed another log who print 3
# Then it's not the only way
Before we are learning about how the promises are, work and when to use it. Now we are keep doing that but with more new ways to manage a response from a promise.
In 2017 was introduced in javascript two new reserved word await
and async
the idea behind that it's simplify and be more descriptive about how to process a promise.
Look back on in the last example
const timePromise = new Promise((resolve, reject) => {
setTimeout(afterTwoSeconds = () => {
resolve('2');
}, 2000)
})
const inOrderPrint = () => {
console.log('1');
timePromise
.then(resolveResponse => console.log(resolveResponse))
.then(() => console.log('3'));
}
We can rewrite this with the new reserved word
const timePromise = new Promise((resolve, reject) => {
setTimeout(afterTwoSeconds = () => {
resolve('2')
}, 2000)
})
const inOrderPrint = async() => {
console.log('1')
console.log(await timePromise)
console.log('3')
}
If you notice in the code above we change the function as async
in their definition, this word tells the function that inside will be a async call.
And when you call the promise, you just await for that.
So if now we want to fetch something we can write the code from the next two ways
const getLatestEarthquakeonChile = () => {
let latestEarthquake = null
fetch('https://api.gael.cl/general/public/sismos')
.then(response => {
const [latest] = response;
latestEarthquake = latest;
})
.then(() => {
console.log(JSON.stringify(latestEarthquake));
})
.catch((error) => {
console.log('error', error);
})
}
Or with async
and await
const getLatestEarthquakeonChile = async () => {
const [latestEarthquake = ''] = await fetch('https://api.gael.cl/general/public/sismos')
console.log(JSON.stringify(latestEarthquake))
}
How you can see the code above get simplify, but we don't catch the error, on the way that the fist code show us. In order to do that we had to wrap in one try/catch.
const getLatestEarthquakeonChile = async () => {
try {
const [latestEarthquake = ''] = await fetch('https://api.gael.cl/general/public/sismos');
console.log(JSON.stringify(latestEarthquake));
} catch (error) {
console.log('error', error);
}
}