In our starter files, open the index.html page from this lessons folder:
10.Async-JavaScript > 01.A-little-bit-of-background
This section has some potentially confusing words such as callbacks, asynchronous, synchronous, and some concepts which may be difficult to understand without knowing a little background as to why we use them.
So first, we will cover what they mean, and what exactly each one does.
A concept to understand is that each line of code is like a task, and each one is read in order, looking at this example:
const heading = document.querySelector('h3');
heading.innerText = ‘Hello’;
haeding.id = ‘main’;
The browser will read line 1, wait for this to be processed, then move onto line 2, wait for this to finish, before moving to line 3. This is referred to as synchronous code.
On a tiny program like this, it does not really matter because the operations are quick and easy to process, and you would not notice any waiting time between each line. But, in an extreme case, if one line never finished processing, or took a long time, then it would block the remaining lines from running.
Over to the starter project to see an example:
// EXAMPLE 1
<button>Let's begin...</button>
<h3></h3>
<img src="" alt="" />
<script>
const button = document.querySelector('button');
const heading = document.querySelector('h3');
button.addEventListener('click', function () {
alert('show me something!');
heading.innerText = 'HEEEEEEYYYYYY!!!!!!';
});
</script>
The first example has a button and a heading in the HTML. Ignore the image for now, this is for the next example.
We select both elements using JavaScript, then the next line adds an event listener to the button. An alert
is shown, then the text for the heading is set when clicked on.
Alerts can be good for these examples because an alert
will block the execution of the code which follows, until we close the alert
in the browser.
Open the browser and test this out.
The first lines of JavaScript will be run, and the button will receive an event listener. Click on the button, and you will see the alert. Then close this down to see the heading text appear. This clearly shows the order in which the code is ran inside of the function. First, we have the alert, then the heading text follows.
So, we have a clear order which things run. And each line will not run until the previous one has completed, and this is how synchronous code works.
One of the issues with synchronous code is that a single line of code can block the rest of the program from running.
And this can be avoided by using asynchronous code. The code is still read in order, line by line. However, an operation does not have to be complete before moving onto the next line. All of the code lines are excecuted one by one, and we then need to handle what to do when each task is completed.
And this is a key part here, handling what happens if the code comes back a success, or if there was an error.
Looking at example 2 here:
const imageSrc = fetch(
'https://upload.wikimedia.org/wikipedia/commons/thumb/7/7d/Kamenn%C3%A1_l%C3%BAka_03.JPG/2560px-Kamenn%C3%A1_l%C3%BAka_03.JPG'
);
We have here something called fetch
.
This is the Fetch API, remember from earlier we have certain web API’S such as canvas
. The Fetch API allows us to fetch things across a network. This could be another website, a database, a server, or an external API somebody has created.
An important thing here is the fetch
call is asynchronous. It will run, and then allow the rest of the code below to run before it completes, or the data is returned. The idea is we get data from somewhere other than our own app. This example selects an image from Wikimedia and stores it into a variable.
Log this to the console to see the result:
const imageSrc = fetch(
'https://upload.wikimedia.org/wikipedia/commons/thumb/7/7d/Kamenn%C3%A1_l%C3%BAka_03.JPG/2560px-Kamenn%C3%A1_l%C3%BAka_03.JPG'
);
console.log(imageSrc);
You will see the following result in the console:
Promise {<pending>}
Promise
Returned is a JavaScript Promise
object that is pending
. What could this be all about?
We will look at promises in more detail soon, but is goes back to the important point mentioned before. With asynchronous code, or async for short, we need to handle what happens if the code returns a success, or if there was an error. And a Promise can handle this.
We don’t know if the Wikimedia site is down, running slow, or if here is a connection problem between us, and the server where the image is stored.
The console log was immediately after the fetch
call, so it was run before the image came back, which is why it was in a pending state, we never had an image available yet to log. We need more time for the image to be requested before attempting to access it.
Modify this example to wait three seconds before logging to the console:
const imageSrc = fetch(
'https://upload.wikimedia.org/wikipedia/commons/thumb/7/7d/Kamenn%C3%A1_l%C3%BAka_03.JPG/2560px-Kamenn%C3%A1_l%C3%BAka_03.JPG'
);
setTimeout(function () {
console.log(imageSrc);
}, 3000);
The console now shows the Promise as fulfilled:
Promise {<fulfilled>: Response}
This time the promise is fulfilled, and we have a response as the result. Waiting for the log has gave us the time to get back what we need.
If this was synchronous code, the rest of the code would need to wait on the image coming back, even if it did not need to use it. This could cause unnecessary delays.
Without a Promise
, the line immediately below fetch
could try to access the image before it is available, causing an error. And we will look at promises and other ways to handle a response next.