Dismiss Modal in Nativescript Angular Can Take Multiple Seconds to Respond
还没有人认领这个 Issue。
评估
- 难度
- 4/5
- 预计耗时
- 3-5 天
- 新手友好度
- 35/100
- Issue 类型
- 缺陷
- 描述清晰度
- 基本清楚
- 活跃度
- 停滞
- 技术栈
- angular, typescript
- 领域
- mobile-dev
调研方向
从 nativescript-core/ui/core/view-base/view-base.ts 中的 _dialogClosed 开始,跟踪其 eachDescendant 遍历。在 iOS 上使用嵌套的 Angular ng-content 于非全屏 modal 中重现该问题,然后验证将其关闭不再导致数百万次调用或持续数秒的延迟,包括通过滑动关闭时也是如此。
由索引模型根据 Issue 内容生成。
描述
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:

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.
- 主要语言
- TypeScript
- 星标
- 25.7k
- 派生
- 1.7k
- 平均合并
- 1 天 5 小时
- 30 天内合并 PR
- 35
贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
NativeScript/NativeScript 的其他 Issue
-
难度 2/5 1-3 小时 新手友好度 65/100
NativeScript/NativeScript#11068 ·
-
bug-pending-triage
难度 3/5 1-2 天 新手友好度 66/100
NativeScript/NativeScript#11436 ·
-
难度 4/5 3-5 天 新手友好度 45/100
NativeScript/NativeScript#11421 ·
-
bug-pending-triage
难度 3/5 1-2 天 新手友好度 52/100
NativeScript/NativeScript#11415 ·
-
bug-pending-triage
难度 3/5 1-2 天 新手友好度 48/100
NativeScript/NativeScript#11374 ·
查看 NativeScript/NativeScript 的全部 Issue
相似的 Issue
-
bug
难度 2/5 1-3 小时 新手友好度 72/100
-
难度 1/5 1 小时以内 新手友好度 85/100
-
check:passed streams:add
难度 2/5 1-3 小时 新手友好度 68/100
-
难度 2/5 1-3 小时 新手友好度 76/100
-
难度 2/5 1-3 小时 新手友好度 68/100