Angular 服务器端渲染应用一个常见的内存泄漏问题

本文探讨了Angular服务器端渲染应用中一个常见的内存泄漏问题,由于未正确处理订阅,导致间隔任务在服务器销毁后继续运行。解决方案是利用ngOnDestroy钩子在组件或服务销毁时退订。此外,还分析了屏幕闪烁问题的原因,当Angular客户端重新渲染服务器生成的HTML,导致用户短暂看到白屏。最后,提到了在某些情况下需要手动干预终止服务器端渲染的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

考虑如下的 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 时,参考下列代码:

github.com/angular/ang…

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); ... 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值