Angular 服务器端渲染应用常见的内存泄漏问题小结
考虑如下的 Angular 代码:
import { Injectable, NgZone } from "@angular/core"; import { interval } from "rxjs"; @Injectable() export class LocationService { constructor(ngZone: NgZone) { ngZone.runOutsideAngular(() => interval(1000).subscribe(() => { ... })); } }
这段代码不会影响应用程序的稳定性,但是如果应用程序在服务器上被销毁,传递给订阅的回调将继续被调用。 服务器上应用程序的每次启动都会以 interval 的形式留下一个 artifact.
这是一个潜在的内存泄漏点。
这个内存泄漏风险可以通过使用 ngOnDestoroy 钩子解决。这个钩子适用于 Component 和 service. 我们需要保存 interval 返回的订阅(subscription),并在服务被销毁时终止它。
退订 subscription 的技巧有很多,下面是一个例子:
import { Injectable, NgZone, OnDestroy } from "@angular/core"; import { interval, Subscription } from "rxjs"; @Injectable() export class LocationService implements OnDestroy { private subscription: Subscription; constructor(ngZone: NgZone) { this.subscription = ngZone.runOutsideAngular(() => interval(1000).subscribe(() => {}) ); } ngOnDestroy(): void { this.subscription.unsubscribe(); } }
屏幕闪烁问题
用户的浏览器显示从服务器渲染并返回的页面,一瞬间出现白屏,闪烁片刻,然后应用程序开始运行,看起来一切正常。出现闪烁的原因,在于 Angular 不知道如何重用它在服务器上成功渲染的内容。在客户端环境中,它从根元素中 strip 所有 HTML 并重新开始绘制。
闪烁问题可以抽象成如下步骤:
关于正在发生的事情的一个非常简化的解释:
(1) 用户访问应用程序(或刷新)
(2) 服务器在服务器中构建html
(3) 它被发送到用户的浏览器端
(4) Angular 重新创建
应用程序(就好像它是一个常规的非 Angular Universal 程序)
(5) 当上述四个步骤发生时,用户会看到一个 blink 即闪烁的屏幕。
代码如下:
// You can see this by adding: // You should see a console log in the server // `Running on the server with appId=my-app-id` // and then you'll see in the browser console something like // `Running on the browser with appId=my-app-id` export class AppModule { constructor( @Inject(PLATFORM_ID) private platformId: Object, @Inject(APP_ID) private appId: string) { const platform = isPlatformBrowser(this.platformId) ? 'in the browser' : 'on the server'; console.log(`Running ${platform} with appId=${this.appId}`); } }
无法通过 API 的方式终止渲染
什么时候需要人为干预的方式终止一个服务器端渲染?
始终明确一点,渲染应用程序的时间点发生在应用程序 applicationRef.isStable 返回 true 时,参考下列代码:
function _render<T>( platform: PlatformRef, moduleRefPromise: Promise<NgModuleRef<T>>): Promise<string> { return moduleRefPromise.then((moduleRef) => { const transitionId = moduleRef.injector.get(ɵTRANSITION_ID, null); if (!transitionId) { throw new Error( `renderModule[Factory]() requires the use of BrowserModule.withServerTransition() to ensure the server-rendered app can be properly bootstrapped into a client app.`); } const applicationRef: ApplicationRef = moduleRef.injector.get(ApplicationRef); return applicationRef.isStable.pipe((first((isStable: boolean) => isStable))) .toPromise() .then(() => { const platformState = platform.injector.get(PlatformState); ...
到此这篇关于Angular 服务器端渲染应用一个常见的内存泄漏问题的文章就介绍到这了,更多相关Angular内存泄漏内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
对angularjs框架下controller间的传值方法详解
今天小编就为大家分享一篇对angularjs框架下controller间的传值方法详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧2018-10-10Angular.JS判断复选框checkbox是否选中并实时显示
最近因为工作需要做了一个选择标签的功能,把一些标签展示给用户,用户选择自己喜欢的标签,就类似我们在购物网站看到的那种过滤标签似的,所以这篇文章就给大家介绍了Angular.JS判断复选框checkbox是否选中并实时显示的方法,下面来一起看看吧。2016-11-11Angular设计模式hierarchical injector实现代码复用模块化
这篇文章主要为大家介绍了Angular设计模式hierarchical injector实现代码复用模块化示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪2023-10-10Angular中使用ng-zorro图标库部分图标不能正常显示问题
这篇文章主要介绍了Angular中使用ng-zorro图标库部分图标不能正常显示问题,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下2019-04-04angularJS 发起$http.post和$http.get请求的实现方法
本篇文章主要介绍了angularJS 发起$http.post和$http.get请求的实现方法,分别介绍了$http.post和$http.get请求的方法,有兴趣的可以了解一下2017-05-05
最新评论