I am having a hard time understanding why a loading overlay isn’t showing immediately.
The overlay is being created and presented at the beginning of the function that switches to a different view. The function is called when a div is tapped:
After I tap the current view does nothing for a couple of seconds, then opens the new view and presents the loading overlay very briefly. I would like the loading overlay to be there all the time while the openPage() function is executing.
Can any of you please explain what I’m missing here? I’m using Ionic 2.2.1.
I think you’d be better off showing the loading controller in the constructor of your new page. The new page should show instantly, even if the content of the page takes a while to load.
You’re dismissing it in the wrong place, you should dismiss after whatever slow stuff is completes. Also, no slow stuff should be in the constructor, move those out into a lifecycle event.
This means that between the tap event on the original view and the present() of the loading overlay there’s very little code.
My only explanation for the delay between the tap and the new page shows up is that it’s happening inside Angular/Ionic while processing the tap event and calling the handler function.
Original page view
<ion-card *ngFor="let thing of things">
<div class="details" tappable (tap)="openThing(thing)">
<ion-card-header class="name">{{thing.name}}</ion-card-header>
<ion-card-content [hidden]="thing.items.length == 0">
(... some content in here...)
</ion-card-content>
</div>
</ion-card>
The thing object can be quite big and it’s the one that takes time loading in the new page. Is it possible that Angular/Ionic take time processing the event due to its size?
Can you elaborate on what (beefy code) is? Is it asynchronously loading data? If so you can’t just hide the loader on the next line, you have to hide it when the async call completes. I guess I can’t imagine what else it would be…if you’re just getting already loaded data and it’s still super slow then it could be render time if it’s a huge loop. That just seems less likely.
Unfortunately I have no idea how to profile Angular applications, I think I’ll have to invest time on that. I suspect that the 2/3 seconds delay is happening before the push to the new page even happens.
My two cents: I never store loading components (or toasts or modals or other such) as object properties. It makes you prone to ownership bugs that programmers working in garbage-collected languages by and large don’t have to worry about.
The same function should always be responsible for creating, popping, and dismissing loading components. If that means you have to refactor your code, so be it. Always make them lexically-scoped variables.
let loading = this._loadings.create();
loading.present();
doBeefyThing().then(() => {
loading.dismiss();
});
Hmm, usually that delay will happen before the push if you have stuff in the constructor, because it has to run that when it builds the page. That’s why I had you move it out of the constructor.
Why don’t you set a breakpoint at the start of the “beefy” code and see how long it takes to hit that? If it hits it instantly it’s the beefy code, if it takes 2/3 then it’s before that. That’s easier than profiling, but you could definitely still profile it just using the chrome profiler.
I just got more confused. I did some (logging-based) profiling and the app is spending 1.5 seconds between the end of the new page constructor and the calling of the ionViewDidLoad()!
Does any of you understand what might be happening? My beefy code isn’t beefy after all, it only takes a few milliseconds!
I found a way to mitigate the problem from the LoadingController perspective. I still need to work on why it takes 1.5 seconds between running the constructor and ionViewDidLoad().
Ionic somehow prioritises the presentation of the layers and it’s not guaranteed that the loading overlay is displayed after the present() function is called. In fact, it returns a promise and, although the documentation doesn’t mention it, I checked the code and the promise only returns when the overlay is shown.
So, following rapropos advice and knowing that it was the new page loading that was the beefy thing here, I arranged things the following way: