One of the most common things that I see people get tripped up on when learning Ionic is the difference between synchronous and asynchronous tasks and how to appropriately handle results from an asynchronous task.
People may often be led to believe that something in their code or the Ionic framework is broken because they aren’t getting the values they expect when in reality they are just attempting to access certain values before they have been set because it relies on some asynchronous method.
In this article, I am going to discuss the difference between asynchronous and synchronous code, and some common situations that you might run into in an Ionic application.
The Difference Between Synchronous and Asynchronous
Before we get into discussing how to deal with asynchronous code in Ionic, we should cover what the difference between “synchronous” and “asynchronous” even is. In short, “synchronous” tasks in a program are executed right away, whereas “asynchronous” tasks are executed later. That means that if you had a program that looked like this:
someSynchronousFunction();
someAsynchronousFunction();
someOtherSynchronousFunction();
These functions would be called in the order that they appear, but since someAsynchronousFunction
will be executing some asynchronous code, both of the synchronous functions will finish their tasks before someAsynchronousFunction
finishes executing its tasks.
Here’s an illustration of what is happening behind the scenes:
Any asynchronous tasks are placed in the event queue to be executed later and any synchronous tasks are placed in the stack to be executed right away. This thing called the event loop* will execute any tasks that are in the **stack, and when there is time, the event loop will place tasks from the event queue into the stack to be executed.
The end result is that asynchronous tasks in your application will finish after synchronous tasks, even if they were called first. This situation can cause some confusion if you don’t understand this situation fully.
Dealing with Promises
One of the first times people run into issues with asynchronous code is with the Ionic Storage
service. When retrieving data from storage using the get
method, an asynchronous request is made to load the data. Instead of returning the data directly, the get
method will return a Promise
that resolves
with the data when the asynchronous task has completed.
When attempting to use this service, people may do something like this:
let username = this.storage.get('username');
console.log(username); // This will NOT work
and expect that the username will be retrieved from storage and then logged out to the console. This won’t work though. The username
variable doesn’t contain the value from storage, it contains the Promise that will eventually resolve with that data (and at this point in time, it will not have resolved yet).
Instead, you need to handle the promise like this:
this.storage.get('username').then((result) => {
console.log(result); // This will work
});
This adds a handler for when the Promise that get
returns resolves, and it will log the data that the promise resolves with to the console. This will work because the console.log
statement is only triggered after the asynchronous task has completed.
However, this can lead to more confusion. Once people understand that they need to handle the response in this manner, they may try to do something like this:
this.storage.get('username').then((result) => {
this.username = result;
});
console.log(this.username); // This will NOT work
The promise is being handled correctly and the result is being assigned to this.username
which is fine, but then we are attempting to log out that value immediately after the asynchronous task is called. Since the get
call is asynchronous, and the console.log
is synchronous, the console.log
is going to execute before this.username = result
is called – even though it appears first.
So, even though there is some appropriate handling of the asynchronous function, we are still attempting to access it in a synchronous manner which will not work no matter how you structure it. In order for it to work, whatever it is that is making use of the result
must be triggered from inside of the .then()
handler.
Dealing with Observables
You may also run into this situation with Observables, the concept is pretty much the same but it looks a little different. In this case, people run into trouble with observables initially when attempting to use the Http service.
Similarly to how people may mistake the ‘Promise’ itself for the data is resolves with, people often also confuse ‘Observables’ with the data that they emit. For example, people may do something like this:
let data = this.http.get('some/api/path'); // This will NOT work
Again, it looks reasonable enough but the get
method is asynchronous and it will return an Observable, not the data that is being loaded in from the server. The correct way to handle an observable is like this:
this.http.get('some/api/path').subscribe((data) => {
console.log(data); // This will work
});
The way in which this is handled is very similar to a promise, except that we subscribe
to the Observable. There are a few more differences between Observables and Promises, but not much more you need to know in the context of this tutorial. If you are unfamiliar with Observables, I would recommend taking a look at An Introduction to Observables for Ionic.
As one final example, just like with Promises you can not do this:
this.http.get('some/api/path').subscribe((data) => {
this.data = data;
});
console.log(this.data);
This is the same situation where the get
call is asynchronous, but the console.log
statement is synchronous. So, even though the get
request is launched first, the console.log
statement will be called before this.data
has been set.
Summary
I think the example of making HTTP requests is a little more obvious because it is somewhat intuitive to know that you are not going to instantly be able to access something that you are loading from a server. However, even code you execute completely locally can still be asynchronous and it may not be so obvious that the code is being executed later.
It is one of those concepts that can take a little while to ‘click’ but once it does it likely won’t cause you many problems.