Tutorial hero image
Lesson icon

Ionic Framework Is Fast (But Your Code Might Not Be)

11 min read

Originally published May 07, 2018

I don't want this article to come across as a self-righteous rant, or that I'm attacking people who have made statements like the ones I will use as examples in this article. The last thing I want to do is sound elitist or fan the flames of framework wars. So, I will precede this article with a little disclaimer:

I'm not making any claims that Ionic is the best framework, or that Ionic is better than native apps, or that you should use Ionic for everything. I'm also not attempting to shame anybody for the code they write, and I'm certainly not insinuating that people shouldn't build and release Ionic applications if they can't do it well (quite the opposite, actually).

The point that I am trying to make in this article is that when it comes to performance problems, more often than not it is a problem with the way the application is coded, not because of Ionic. There is a point where the performance of Ionic itself (and more specifically, running code through a browser) comes into play, but a lot of the time people aren't anywhere near those limitations when discussing the performance of Ionic.

The key points that I will be discussing in this article are:

  • Creating high performing Ionic applications requires expertise both in Ionic and general web performance concepts. This takes time and experience to learn.
  • Creating decently performing Ionic applications is generally achievable with just a basic level of knowledge
  • Assuming issues are your own fault (even if it turns out it's not) and attempting to fix them is a good way to grow as a developer
  • Applications that do not perform well can still provide value
  • Performance problems are usually the fault of the application, not the framework

I'll be beginning by explaining my thoughts on these points, and I'll finish by giving you some practical examples of solutions to common performance problems in Ionic applications. These examples range from simple changes that can easily be overlooked, to more complex examples that require a much deeper understanding of how web browsers work. All the solutions will have one thing in common: they are all performance improvements that fall under the responsibility of the developer.

Outline

It Doesn't Matter How Performant the Framework Is, If Your Code Isn't

One thing specifically that prompted me to write this article was the discussion around Ionic 4 coming out. I kept seeing questions from people who are dissatisfied with the performance of their Ionic applications currently and are asking if Ionic 4 will bring performance improvements.

The answer was: yes. Ionic 4 would be faster than Ionic 3 (quite significant improvements were made) and generally every new framework version comes with some form of improvements. But, Ionic 3 already was fast (as was Ionic 2, and even the original Ionic built on AngularJS). If you are holding out for a new framework version because your application currently has a 10 second launch time, taps are slow to respond, and pages stutter and take a long time to load then you are going to be disappointed. The current version of the framework is already perfectly capable of building applications that do not have these problems. These issues would likely be problems with your code, and it doesn't matter how much faster Ionic 4, or 5, or 6, or 20, is... no amount of performance increase will fix that.

I think an interesting analogy is the case of the super suits that were being used in competitive swimming. For a period of time, athletes were wearing these high-tech swimming suits made from specialised materials that would allow them to swim faster in the water. This caused a lot of controversy and they were eventually banned.

These suits did lead to increased performance, but we're talking about seconds or even fractions of seconds of improvement here. If I were to use one of these suits it would be practically pointless, because a competitive swimmer without one of these suits would still probably lap me three times in a 200m race. There are much more critical and impactful issues I need to focus on before worrying about the gear I wear in the pool.

It's the same with Ionic. New versions of a framework may bring significant performance improvements, but if your code is not already designed well and operating efficiently, then any improvements are probably going to be insignificant in comparison. Focus on improving your swimming, before you worry about super suits.

Assume Responsibility

I don't want to get too preachy here (maybe it's a little late for that anyway), but a mindset that has served me well in life is assuming responsibility for things (even if they may not be my responsibility). It gives you the power to make changes and improve. This is a mindset I always have (or at least, try to have) when coding. It's so easy to get frustrated and blame the tools, the framework, or other developers, but it is much more productive to take responsibility yourself.

If you run into something that you think is a bug, assume that it's a mistake you made. Investigate the cause and debug to the best of your ability. If you solve the problem you can now quickly move on with your work, and you probably would have learned a thing or two you wouldn't have otherwise. If it does indeed turn to be a bug in the framework or tools you are using, you now have something valuable to contribute back (a more detailed issue report, or maybe even a fix) and you still would probably have learned some interesting things.

If your application is performing slowly, assume that it is an issue with your code. Unless we are in the realm of very small optimisations, then chances are it is your code that is the issue anyway. If you assume responsibility for it and start looking for ways to improve performance, then you are going to start learning some interesting performance concepts that will make you a better developer.

It's easy and good for our egos to shift blame onto someone or something else, and it's certainly easier to say to your boss:

It's a limitation of the framework. The framework we are using just doesn't perform very well.

rather than:

My code isn't designed as well as it could be, and I'm not sure how to fix it right now.

Sometimes, you won't know that you haven't designed something the best way possible, especially if you are a beginner. But I think it is a much better mentality to assume that it is always your fault, as it gives you the power to search for a solution and improve as a developer.

Ionic Does Not Make Creating High-Performance Applications Easy

The Ionic Framework makes creating applications much more accessible to a lot of people. Mobile applications can realistically be created by developers who may only have reasonably basic knowledge of web tech. The applications may not look that great, or perform that well, but they can work well enough to achieve valuable goals.

I have always seen this as a bit of a double-edged sword for Ionic. This accessibility has opened up the door for thousands of people to create applications where they otherwise may not have. However, many of these applications are not designed as well as they could be, and inevitably you have a lot of clunky, slow, poor performing applications built with Ionic floating around. This is a good thing. Just because an application is slow, or ugly, or frustrating to use, it doesn't mean that it provides zero value. It does, however, create a bit of a reputation problem for Ionic if there are a lot of poorly performing Ionic applications around due to that low barrier to entry, people may get the impression that this is a problem with Ionic.

Creating a complex Ionic application that performs well requires specialised knowledge and expertise.

It's probably going to take a comparable amount of time and expertise to develop the application any other way (natively, or with any other framework). To me, the main benefit of Ionic is not that it makes developing applications easier (although, I do very much like using web tech and developing in the browser). The benefit is mostly in Ionic's portability running on web tech means the same codebase can work anywhere the web does. With Ionic, we can get an iOS application, an Android application, a standard website or Progressive Web Applications, and even a native desktop application all for the same price. Who knows where we might want our applications to run in the future, but I'd say there is a strong chance web tech isn't going to be disappearing any time soon.

Although I see that as the main benefit of Ionic to developers looking to master what Ionic can do, the fact that Ionic makes it easier to create "decently" performing applications is the main benefit for a lot of people.

If your application does not require top-notch performance, then you can get away with just basic knowledge. If you need a high-performance application, then you are going to need to invest the time into learning how advanced browser concepts play into application performance.

Common Sources of Performance Issues in Ionic Applications

I said I didn't want to sound too preachy, so let's switch gears into some practical information that you might be able to implement in your applications. I'm going to walk through some common things that can be the source of performance problems in Ionic applications. We're going to start with the relatively simple stuff that has a huge impact on performance, through to more obscure stuff that requires a lot more intimate knowledge of how the web works.

We are only going to touch on these concepts briefly, otherwise, this article would be far too long. If you are interested in tackling more advanced performance concepts in Ionic, this is something the Creating High Performance Ionic Applications module covers extensively.

Lazy Loading

Lazy loading is a simple but powerful concept, and it is something I would advise all developers use. The basic idea is that rather than loading your entire application on boot, it will only load what is required at the time (i.e. it only loads what is necessary for your first page). Additional resources can be preloaded in the background after the application has booted, or loaded on demand (only if they are accessed).

Imagine going to a website that loaded every single page on the website into memory when you visited the home page. You just wouldn't do that. But if you have an Ionic application that has 10 pages, and you don't use lazy loading, then that is exactly what you are doing with those 10 pages. If your application takes more than a couple of seconds to boot then this is often the issue.

If you are using lazy loading then it doesn't really matter how big your application is, you should still be able to launch it quite fast. Here's a good example:

The example conference application used in the example is quite complex, but it is still able to boot very quickly.

Make a Production Build

Throughout development, we generally use a debug build. The code is intentionally left unoptimised to make it easier to debug. Although it is easier to debug, it will not perform as well as an optimised build.

All you need to do is add the --prod flag to the end of your run or build command, and you will likely see a big performance increase. This is something that everybody should be doing, but it's something that people could easily miss.

Splash Screen

If you are using Capacitor, the splash screen for your application has a default timeout of 5 seconds I believe. This means that no matter what, your application is going to take 5 seconds to finish "booting" (even though it will have already loaded in the background). Instead of letting the Splash Screen time out, you should manually hide it whenever your application is "ready". When that is will depend on your application it might be as soon as the first bit of code runs in your application, or you might want to do something else first.

All you need to do is use the Splash Screen API to hide the splash screen as soon as your application is ready. Just call SplashScreen.hide() and the splash screen will dismiss as soon as it hits this code.

Blocking

Blocking is a performance killer. This is what happens when your code stops executing as it is waiting for something else to happen first. Let's say that you are loading some data from a server, and that request takes three seconds to complete.

You could make Ionic a million times faster, but that request is always going to take three seconds to complete.

A good way to handle this is to allow the request to run in the background whilst your application goes on doing its thing (e.g. using a promise or observable to handle the request asynchronously, and deal with the returned data whenever it is available). A bad way to handle this is to make your application wait for the response to return until doing anything else.

If your application absolutely needs this data loaded before anything else can happen, make sure that you are still performing the request asynchronously and display something friendly to the user (so that they know what is happening), rather than just having the application freeze up for three seconds. Even if the request takes 0.2 seconds to complete, if you are blocking the execution of your application it is going to make it feel slow and clunky.

Browser Rendering Process

One of the key aspects of building high-performance applications is understanding the browser rendering process. This is something I talk about extensively in the Creating High Performance Ionic Applications module. It is an in-depth process, but I'll try to give a quick rundown here.

Basically, the browser rendering process is the steps the browser needs to take in order to display something on the user's screen. It goes like this:

Browser Rendering Process

Image from developers.google.com licensed under the Creative Commons Attribution 3.0 License

First, something happens (typically triggered by JavaScript code) to make a visual change to the application. The browser now needs to calculate what the style for each element on the page should be (taking into account all of your CSS classes, and perhaps CSS classes that overwrite other CSS classes). Next, the layout step calculates the positions of every element on the screen. Then the pixels are painted onto the screen, and finally, the "layers" are composited in the correct order and position (i.e. you might have things with a different z-index overlapping each other).

Each step in this process has a cost, the more steps you trigger, the higher the cost. If your code only needs to perform the paint/composite steps, then this is relatively "cheap" in terms of performance. If your code triggers a "layout" then this is going to be a lot more expensive. The goal is to trigger this process as few times as possible, and to perform as few steps of the process as possible each time. If the browser needs to do too much work, then it won't be able to paint to the screen quickly enough to make your application look fast and smooth (i.e. 60fps or 60 "paints to the screen" per second).

There are simple mistakes you can make that will mess up this process and kill performance, one particularly good example being layout thrashing. Basically, layout thrashing occurs where we are rapidly triggering the layout step in the browser rendering process (this is a common occurrence when making modifications to the page in response to scroll events, since they are fired off so rapidly).

Bloating the DOM with too many elements at a time can cause issues, as the browser has to do a lot more work to calculate the styles and positions of everything on the page. Animations are another common cause of issues. Ionic applications are perfectly capable of implementing performant animations (with some limitations), but if they are done incorrectly, they can drastically slow down your application.

For example, in this video I walk through an example of an animation that performs well, and an animation that performs poorly.

This code:

@keyframes moveWithMargin {
  0% {
    margin-left: 0;
  }

  50% {
    margin-left: 20px;
  }

  100% {
    margin-left: 0;
  }
}

is terrible for performance, because it will trigger layouts.

This code:

@keyframes moveWithTransform {
  0% {
    transform: translateX(0);
  }

  50% {
    transform: translateX(20px);
  }

  100% {
    transform: translateX(0);
  }
}

...is great for performance, because it won't trigger the layout step. They both achieve the exact same visual affect. Again, this isn't something that is going to be obvious to a beginner. You could have lots of things like this strung throughout your codebase, slowing your application down, but you might have no idea that its a problem.

These are just a couple of examples, there is far more to know about the browser rendering process, and it is by understanding this process in more depth that you will start to get to the high ends of performance in your Ionic applications.

Summary

The issue with a lot of the stuff I have talked about is that you don't know what you don't know. You could read up on the basics, follow a few tutorials, and it may seem like you are doing everything correctly. However, there still may be many factors affecting the performance of your application that you don't even realise. This is why it is easy, and why it is understandable, to assume that the problem lies with the framework you are using. The key takeaway from this article is that Ionic is a solid framework, and a lot of people have built a lot of high performing applications with it. It does have its limitations, but for most applications, most performance issues are likely due to the way the application is coded.

If high performance is your goal, you can achieve that with Ionic. You just need to invest the effort into learning advanced performance concepts.

If you enjoyed this article, feel free to share it with others!