動態

詳情 返回 返回

使用 RxJS timeout 操作符給 Angular SSR 服務器端渲染模式下的 HTTP 請求添加超時機制 - 動態 詳情

Angular Universal 是一個開源項目,擴展了 @angular/platform-server 的功能。 該項目使 Angular 中的服務器端渲染成為可能。

為了在服務器上渲染,Angular 使用 node.js 的 DOM 實現——domino. 對於每個 GET 請求,domino 都會創建一個類似的 Browser Document 對象。 在該對象上下文中,Angular 初始化應用程序,然後向後端發出請求,執行各種異步任務,並將任何來自組件的更改檢測應用到 DOM,同時仍在 node.js 環境中運行。渲染引擎隨後將 DOM 序列化為字符串並將字符串提供給服務器。服務器將此 HTML 作為對 GET 請求的響應發送。 服務器上的 Angular 應用程序在渲染後被銷燬。

使用 Angular Universal 進行服務器端渲染,最常見的一個問題就是,用户在網站上打開一個頁面並看到一個白屏。翻譯成 Web 應用領域的術語來説,就是首字節時間(Time to First Byte, 簡稱 TTFB) 過大。TTFB 是指從瀏覽器請求頁面,到它從服務器接收到第一個信息字節之間的時間。在這種情況下,瀏覽器確實想從服務器接收響應,但請求以超時結束。

在分析這個性能問題之前,我們有必要了解 Zone.js 和 ApplicationRef.

Zone.js 是一個允許開發人員跟蹤異步操作的工具。在它的幫助下,Angular 創建了自己的 Zone 並在其中啓動應用程序。在 Angular 區域中的每個異步操作結束時,都會觸發更改檢測。

ApplicationRef 是對正在運行的應用程序(文檔)的引用。在這個類的所有功能中,我們對 ApplicationRef.isStable 屬性感興趣。它是一個發出布爾值的 Observable。當 Angular 區域中沒有異步任務正在運行時,isStable 為 true,當有任何異步任務時,isStable 為 false.

因此,應用程序的穩定性,取決於 Angular 區域中異步任務的存在與否。

當應用程序的 ApplicationRef.isStable 第一次變為 true 時, Angular 會渲染當前狀態的應用程序,並清理平台資源。

我們現在可以假設用户正在嘗試打開一個無法達到穩定狀態的應用程序。 setInterval、rxjs.interval 或在 Angular 區域中運行的任何其他遞歸的異步操作,以及 HTTP 請求,都會阻止 Angular 應用進入穩定狀態。

我們可以使用 rxjs 的 timeout 操作符,強制使得一個長時間運行的 HTTP 請求超時。

import { timeout, catchError } from 'rxjs/operators';
import { of } from 'rxjs/observable/of';

http.get('<https://example.com>')
  .pipe(
    timeout(2000),
    catchError(e => of(null))
  ).subscribe()

上面例子的邏輯是,如果 HTTP 請求兩秒內,沒有從服務器端接收到響應,則進入 catchError 錯誤處理模塊內部。

這個解決方案的缺點是,對於每個 HTTP 請求,我們都需要手動為其添加 timeout 操作符。

一種更加優雅的實現是,使用開發包 @ngx-ssr/timeout 裏的 NgxSsrTimeoutModule.

如果模塊被導入 AppServerModule,那麼 HTTP 請求超時將只對服務器端渲染環境起作用。

import { NgModule } from '@angular/core';
import {
  ServerModule,
} from '@angular/platform-server';
import { AppModule } from './app.module';
import { AppComponent } from './app.component';
import { NgxSsrTimeoutModule } from '@ngx-ssr/timeout';

@NgModule({
  imports: [
    AppModule,
    ServerModule,
    NgxSsrTimeoutModule.forRoot({ timeout: 500 }),
  ],
  bootstrap: [AppComponent],
})
export class AppServerModule {}
user avatar yishenjiroudekaixinguo 頭像 rongyunrongcloud 頭像 thinkerdjx 頭像 junction_640ae1a257911 頭像
點贊 4 用戶, 點贊了這篇動態!
點贊

Add a new 評論

Some HTML is okay.