Ionic 3 Performance Boost with Observable using VirtualScroll and WKWebView
What do you do when an application you just installed is f****** slow?
-------> Straight to the garbage, no question asked.
This scenario can also happen to the applications that you develop.
Not everybody has an iPhone 7.
In today's tuts we get this painful issue out of the way.
- The unoptimized case
- The WKWebView solution
- The Ionic 3 VirtualScroll solution
Let's fire up our Ionic 3 app:
ionic start smoothapp blank --v2
The same home.ts file will be used for each case:
import { Component } from "@angular/core";
import { Observable } from "rxjs";
@Component({
selector: "page-home",
templateUrl: "home.html"
})
export class HomePage {
displayedImages;
constructor() {}
ngOnInit() {
const baseImg = "http://lorempixel.com/400/200/";
const imgArray = Array(1000).fill(baseImg);
this.displayedImages = Observable.of(imgArray);
}
}
All the work is done in the ngOnInit hook.
I haven't found a free service that returns 1000 images on demand, so we go back to our good old lorempixel website.
First, we add 1000 image urls to a temporary array named imgArray.
Once this is done, an Observable is returned. A HTTP request now returns an Observable, that's why we return one to simulate this case (you can have a reminder on Observables there).
Using the method of from Observable, the image array will be transformed into an Observable sequence.
Just a good old ngFor
Ionic advises us to use the <ion-img> Component, however, it has some issues with the current VirtualScroll:
https://github.com/driftyco/ionic/issues/9660
So the good old <img> tag will be used to keep the tests congruency.
In the home.html:
<ion-content padding>
<ion-list>
<ion-item *ngFor="let displayedImage of displayedImages | async">
<ion-avatar item-left>
<img src="{{displayedImage}}">
</ion-avatar>
</ion-item>
</ion-list>
</ion-content>
The images are displayed inside an <ion-list>.
The ngFor Directive here creates one <ion-item> for each image we have to display.
The asyncPipe is added because we are not looping on a simple array, but on an Observable sequence.
Finally the images are displayed inside an <ion-avatar>.
The benchmark:
The initial part is the Ionic 3 loading screen with a stable 10 fps.
Once the application is loaded, the fps become unstable, every time a scroll is triggered, a fps drop appears.
It's looking very bad and that's not how a smooth application's benchmark should look like.
Let's fix this ;).
Introducing WKWebView
The WKWebView API was introduced in iOS 8.
It has a better HTML5 support (added IndexedDB and ObjectStore ArrayBuffer) and has far better performances than its predecessor UIWebView.
The whole installation process is available there:
https://github.com/driftyco/cordova-plugin-wkwebview-engine#installation-instructions
From here, 10k images will be displayed. Why? Because we can!
The results are really impressive:
After the initial Ionic 3 loading (the constant 10fps).
The app is working smoothly averaging 55 fps!
All of that without modifying the source code. That's a quick and clean fix!
The Bleeding Edge: VirtualScroll
Finally the Ionic homemade solution: the VirtualScroll.
Unlike the other cases, the VirtualScroll only renders a limited number of rows.
Even though 10K images are available:
Only a few numbers are in the DOM.
This number is just enough to give the user the impression that every images are here.
The only changes are:
<ion-list [virtualScroll]="displayedImages | async">
<ion-item *virtualItem="let displayedImage">
.
.
.
The <ion-list> and the <ion-item>.
We attach the virtualScroll attribute. The displayedImages are required, alongside the asyncPipe (still using our Observable). The virtualItem Structural Directive will do its job but requires the creation of a displayedImage variable.
And that's it!
The performances:
The application is running smoothly while using the good old UIWebView API.
However, this solution comes with some other issues:
https://github.com/driftyco/ionic/issues/8744
Conclusion
We are damn lucky.
Many solutions and improvements have been created for us through the past years.
The VirtualScroll is very interesting because it allows us to virtually display thousands of images without breaking a sweat by only rendering a hundred, however, it does come with its own small issues that can be buzz killers.
On the other side, the WKWebView API is already there since iOS 8 and very stable for some great performances.
Always remember: