Dismiss Modal in Nativescript Angular Can Take Multiple Seconds to Respond

Offen
#8,419 1 Kommentar 2 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

Bewertung

Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Anfängerfreundlichkeit
35/100
Issue-Typ
Bug
Klarheit
Größtenteils klar
Aktivitätsstatus
Veraltet
Tech-Stack
angular, typescript
Bereich
mobile-dev

Rechercherichtung

Beginne in nativescript-core/ui/core/view-base/view-base.ts bei _dialogClosed und verfolge dessen eachDescendant-Traversierung. Reproduziere das Problem mit verschachteltem Angular ng-content in einem nicht vollbildfähigen Modal unter iOS und überprüfe anschließend, dass das Schließen keine Millionen von Aufrufen oder Verzögerungen von mehreren Sekunden mehr verursacht, auch wenn es durch Wischen geschlossen wird.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Beschreibung

os: ios

Environment

  • CLI: 6.4.0
  • Cross-platform modules: 6.4.1
  • Android Runtime: 6.4.1
  • iOS Runtime: 6.4.0
  • Plugin(s):
    Nativescript Angular

Describe the bug
Apps with large numbers of nested angular components in modal views begin to take exponentially longer to close.

This seems to only affect modals presented in non-fullscreen mode. Modals presented in fullscreen seem to be unaffected.

To Reproduce
Make normal use of in Angular. The more items you nest, the larger the delay will be, exponentially.

Currently only tested for iOS.

Additional context
Recently I went back through our app and increased the number of angular components used to better clean up the code base and better make use of Angular components and templating.

I noticed that some modals took an exceptionally long time to close, and began following the stack trace to see what was going on.

I followed it to a statement that calls _dialogClosed() in view-base.ts, and notice that the stack took several seconds to return from this function.

I modified the function to see roughly how many times _dialogClose() would be called:

...
    let ENTRY = undefined;
    let TOTAL_COUNT = 0;

    ViewBase.prototype._dialogClosed = function () {
        if (!ENTRY) {
            ENTRY = this;
            console.log('Beginning _dialogClosed call.');
            TOTAL_COUNT = 0;
        }

        eachDescendant(this, function (child) {
            child._dialogClosed();
            TOTAL_COUNT += 1;
            return true;
        });

        if (ENTRY === this) {
            console.log('Finished notifying children of close. Total count: ' + TOTAL_COUNT);
            ENTRY = undefined;
        }
    };
...

I opened my modal, then closed it and got the following output:

CONSOLE LOG file:///node_modules/@nativescript/core/ui/core/view-base/view-base.js:695:0: Beginning _dialogClosed call.
CONSOLE LOG file:///node_modules/@nativescript/core/ui/core/view-base/view-base.js:706:0: Finished notifying children of close. Total count: 20611107

So in my case this function was called 20611107 times, and causes a delay of about 14 seconds before the modal responds.

Another modal with essentially only an image and label on it encounter a similar issue:

Simulator Screen Shot - iPhone 11 - 2020-03-07 at 21 12 15

CONSOLE LOG file:///node_modules/@nativescript/core/ui/core/view-base/view-base.js:695:0: Beginning _dialogClosed call.
CONSOLE LOG file:///node_modules/@nativescript/core/ui/core/view-base/view-base.js:706:0: Finished notifying children of close. Total count: 872483

This modal sees about a second's worth of delay when closing.

Expected behavior
There should not be a massive performance hit and delay when closing modals with nested Angular components. Rendering these items is essentially instant, and closing the modal should be too.

(Partial) Work Around
You can get around the issue by having Angular delete most of the components before dismissing the modal.

I updated one view to use *ngIf and destroy all content under it when about to close the modal.

Component:

<StackLayout *ngIf="!closing">
      <ng-content></ng-content>
</StackLayout>

Code:

closeModal(): void {
    if (!this.closing) {
     this.closing = true;

      this._ngZone.run(() => {
       // Call in ngZone to ensure Angular is notified of the closing change.

        setTimeout(() => {
         // Delay to allow the *ngIf to update and destroy children.
          this._dismissModal();
        }, 10);
      });
    }
}

This causes the second example modal pictured above to output the following:

CONSOLE LOG file:///node_modules/@nativescript/core/ui/core/view-base/view-base.js:695:0: Beginning _dialogClosed call.
CONSOLE LOG file:///node_modules/@nativescript/core/ui/core/view-base/view-base.js:706:0: Finished notifying children of close. Total count: 43

So by destroying all components before calling dismiss it doesn't have to traverse the chain.

The issue is though if that dismissing via a swipe down gesture doesn't hit this code, so the view will get dismissed but the app will still hang while it called _dialogClosed() recursively.

I've got a workaround for that too, but that's beyond the scope of this ticket and a bit more complex.

Sample project
I will add a sample project when I get a chance, there isn't anything special though. Essentially the second modal component's elements looks like:

<StackLayout>
   <PopupPageView>
     ... // ng-content
      <LoadingView>
         ... // ng-content
         <ExampleModalContent>
            <StylingContentComponent>
               ... // ng-content
                  <Image>
                  <Label>

Only PopupPageView, LoadingView, and StylingContentComponent has an ng-content, along with a 1-2 StackLayouts within.

The ExampleModalContent represents that pictured modal.

The first modal example _dialogClosed calls had 1-2 more nested sections within it.

Vorherrschende Sprache
TypeScript
Sterne
25.7k
Forks
1.7k
Ø Merge
1 T. 5 Std.
Gemergte PRs (30 T.)
35

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
  3. Forken Sie das Repository und arbeiten Sie in einem Branch.
  4. Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.

Mehr aus NativeScript/NativeScript

Alle Issues in NativeScript/NativeScript

Ähnliche Issues

Weitere Issues zu TypeScript

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.