Using Promises
Communication with APIs is one of the most fundamental
functions in modern JavaScript programming; however, in order to use APIs properly
in your application you have to be able to use Asynchronous methods.
Synchronous code executes one after another depending on how it is defined in
the file, and is the standard method of operation for JavaScript and
TypeScript. Asynchronous code; on the other hand, may be defined within other
code, and will execute when a specified delay occurs or a resource is finished
loading.
TypeScript offers two different methods of dealing with
asynchronous methods: Promises and Async/Await - which is a new standard
introduced in ES7 that TypeScript allows you to use. In this lab, we are going
to leverage asynchronous code to fetch cute little robot avatar icons for our movingElement items that we created in the previous labs.
We will be doing the same method two ways, first with Promises, and then with
the new Async/Await standard.
In this exercise, we are going to fetch our avatars with
Promises.
1.
Copy your advancedTypeScriptLab_animated
folder, and name the copy advancedTypeScriptLab_promise.
First, open up your index.html file in your advancedTypeScriptLab_promise
folder in Visual Studio Code.
2.
Since we are going to be using the fetch API - a
new way of creating server requests in JavaScript - we need to make sure to add
a polyfill to our index.html file in case fetch isn't
available in your browser. A polyfill is a script to
ensure that a newer feature implemented in modern browsers is available in
older browsers. To do this, we are going to add a script tag above the
reference to advancedTypeScriptLab.js in our index.html file referencing the
CDNJS copy of the Fetch polyfill.
<html>
<body>
<script
src='https://cdnjs.cloudflare.com/ajax/libs/fetch/2.0.3/fetch.min.js'></script>
<script src='advancedTypeScriptLab.js'></script>
</body>
</html>
3.
Save your index.html file, and then open up your
advancedTypeScriptLab.ts file in your advancedTypeScriptLab_promise folder in Visual Studio Code.
4.
Let's make a method called getAvatar_Promise.
function
getAvatar_Promise (elem: HTMLElement) {
}
Note that we are going to be passing our HTMLElement from the movingElement
class, so we have the call signature typed in that fashion.
5.
Now, in order to make our little robots, we are
going to be using the RoboHash API. We are going to
set our element's backgroundImage to the URL of our RoboHash, then append it to the document.body.
function
getAvatar_Promise (elem: HTMLElement) {
let avatar =
'https://robohash.org/set_set3/somerobot?size=60x60'
elem.style.backgroundImage
= 'url("' + avatar + '")';
document.body.appendChild(elem);
}
This is all fine, but if we were to run this code, all of
our robots would look the same. That's boring! Let's make this more interesting
and make each robot generated completely different.
6.
In order for our robots to be randomly
generated, RoboHash needs a different string passed
to the image name, replacing where we put somerobot
in the avatar variable value. We could just generate a string at random, but
what fun is that? Instead, let's name our robots using an API that returns
random user information - UINames. First - we will
call UINames using fetch.
function
getAvatar_Promise (elem: HTMLElement) {
fetch('https://uinames.com/api/')
let avatar = 'https://robohash.org/set_set3/somerobot?size=60x60'
elem.style.backgroundImage
= 'url("' + avatar + '")';
document.body.appendChild(elem);
}
7.
The fetch command returns what is called a
Promise. If you were to assign this value to a variable and attempt to use it,
it wouldn't work because the value hasn't returned by the server by the time
the next line is called. In order to use a value from a Promise, we need to use
the .then() property of the promise, which will
contain the response from the server.
function
getAvatar_Promise (elem: HTMLElement) {
fetch('https://uinames.com/api/').then(function(response) {
return response.json();
})
let avatar =
'https://robohash.org/set_set3/somerobot?size=60x60'
elem.style.backgroundImage
= 'url("' + avatar + '")';
document.body.appendChild(elem);
}
The response.json()
method transforms the fetch response into a JSON object ready for your code to
use. But we still aren't quite there yet!
8.
Even though we are returning response.json() from our .then(), this return is
still a Promise. In order to use the JSON object returned from the fetch
properly, we need to chain another .then() to use that
value. Then we can get access to the actual data from the server - in this case
we are after the name property. Let's go ahead and make the robots introduce
themselves when they are about to show up on the screen.
function
getAvatar_Promise (elem: HTMLElement) {
fetch('https://uinames.com/api/').then(function(response) {
return response.json();
}).then(function(response)
{
alert('Hi! My
name is ' + response.name);
})
let avatar =
'https://robohash.org/set_set3/somerobot?size=60x60'
elem.style.backgroundImage
= 'url("' + avatar + '")';
document.body.appendChild(elem);
}
Now the robots are announcing themselves, but they still
aren't using the name to generate the avatar, and they are still being added to
the DOM before the server's response is called. The code below the .then() chain is still running synchronously.
9.
To fix that problem, let's move the rest of the
code into the .then() block, and concatenate the
response.name property into our avatar URL.
function
getAvatar_Promise (elem: HTMLElement) {
fetch('https://uinames.com/api/').then(function(response) {
return response.json();
}).then(function(response)
{
alert('Hi! My
name is ' + response.name);
let avatar =
'https://robohash.org/set_set3/'+ response.name +'?size=60x60'
elem.style.backgroundImage
= 'url("' + avatar + '")';
document.body.appendChild(elem);
})
}
10.
Finally, let's adjust the iterator from the
previous lab for (let elem of standardElements)
to replace document.body.appendChild(elem) with a call to this function. Oh, and let's go ahead
and remove the green background too.
for
(let elem of standardElements)
{
elem.style.width
= "60px"
elem.style.height
= "60px"
elem.style.margin
= "5px"
let elemClass =
new movingElement(elem);
getAvatar_Promise(elemClass.element);
}
11.
Save your file and compile with CTRL+Shift+B since we set up our default compile task in
the previous lab.
12.
Open your index.html file in the browser, and
you should first see each robot announce itself by name, then after a short
while (the image does have to load), it will appear on the screen. When they've
all loaded, it should look something like this:
Hover over them, watch them spin around, and click on them
to watch them move back and forth.
Now you have some cute little spinning robot heads! In
our next exercise, we will convert our function over to using the Async/Await
Method.