當 Resource API 首次問世時,resource
函數傳回一個 promise,而 rxResource
函數只傳回 Observable 的第一個值。在 rxResource 函數中尤其明顯,當
rxResource({
request : this.num,
loader: ({ request: n }) => timer(0, 1000).pipe(take(n))
})
發出一個整數並且結束,而不是 n 個整數。
幸運的是,資源 API 將支援串流傳輸,其中函數可以在 Angular 19.2.0 中傳回多個回應。
rxResource
函數的選項保持不變,但 resource
函數有一個新的選項, stream, 來支援串流。
在這篇文章中,我將示範如何使用 rxResource
和 resource
函數來串流傳輸表格行。
makeARow
RxJS 運算子function makeRows(numRows: number, numElementsPerRow: number) {
return function (source: Observable<number>) {
return source.pipe(
tap((i) => console.log('timer called', i)),
map((num) => Array(numElementsPerRow).fill(0).map((_, index) => (num * numElementsPerRow + index) + 1)),
take(numRows),
)
}
}
makeRows
自訂運算子會填入數字數組,並在填入指定數量的行後取消訂閱。
@let rxResourceTitle = 'Aggregate table rows with rxResource stream';
<ng-container [ngTemplateOutlet]="table" [ngTemplateOutletContext]="{ $implicit: tableDataRxResource, title: rxResourceTitle }"/>
<ng-template #table let-tableResource let-title="title">
<p>{{ title }}</p>
@for (row of tableResource.value(); track $index) {
<div>
@for (data of row; track data; let last=$last) {
@let delimiter = last ? '' : ', ';
<span>{{ `${data}${delimiter}` }}</span>
}
</div>
}
</ng-template>
在 HTML 範本中,我建立了一個 NgTemplate
來顯示表格行和靜態標題。 在 ng-container
元素中,我將模板變數 table
指派給 ngTemplateOutlet
輸入。此外,我將靜態標題和資源值指派給 ngTemplateOutletContext
輸入。
@Component({
selector: 'app-root',
imports: [NgTemplateOutlet],
templateUrl: 'main.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class App {
rowSub = new Subject<number[]>();
table$ = this.rowSub.pipe(
scan((acc, values) => ([...acc, values]), [] as number[][]),
);
tableDataRxResource = rxResource({
loader: () => this.table$,
});
constructor() {
timer(0, 1000)
.pipe(makeRows(10, 10))
.subscribe({
next: (array) => this.rowSub.next(array)
});
}
}
rowSub
是一個發出數字數組的 Subject。 當 rowSub
發出新陣列時,table$
Observable 使用 scan
RxJS 運算子將其附加到巢狀陣列中。
tableDataRxResource
資源由 rxResource
函數建立。此資源有一個 loader,可在表格行到達時進行串流傳輸。
RxJS timer 在建構函式中每秒產生一個新行,並在第十次後停止。 當 Observable 訂閱時,結果會回饋給 rowSub
Subject。
<ng-container [ngTemplateOutlet]="table" [ngTemplateOutletContext]="{ $implicit: tableDataResource, title: 'Aggregate table rows with resource stream' }"/>
<ng-template #table let-tableResource let-title="title">
<p>{{ title }}</p>
@for (row of tableResource.value(); track $index) {
<div>
@for (data of row; track data; let last=$last) {
@let delimiter = last ? '' : ', ';
<span>{{ `${data}${delimiter}` }}</span>
}
</div>
}
</ng-template>
ng-container 使用相同的模板但具有不同的 resource 和靜態圖塊。
table = signal<{ value: number[][] }>({ value: [] });
The table signal holds an object with a value property. The property stores a nested number array.
tableDataResource = resource({
stream: async () => this.table,
});
tableDataResource
資源使用 resource
函數來串流傳輸表格行。 stream
選項是新的,並且需要一個返回訊號 (signal) 的非同步函數 (async function)。
@Component({
...
})
export class App {
table = signal<{ value: number[][] }>({ value: [] });
tableDataResource = resource({
stream: async () => this.table,
});
constructor() {
timer(0, 1500)
.pipe(makeRows(10, 10))
.subscribe({
next: (array) =>
this.table.update(({ value }) => ({ value: [...value, array] }))
});
}
}
RxJS timer 訂閱並將新的數字數組附加到 table
訊號。
resource
函數 與 rxResource
函數演示相同的結果;每秒新增一行。