[英]How to reduce amap Array.prototype.some() calls?
我有一個管理從 SocketIO API 獲取的數據的服務,例如
export class DataService {
private data: SomeData[];
// ...
getData(): Observable<SomeData[]> {
// distinctUntilChanged was used to limit Observable to only emits when data changes
// but it does not seem to change much things...
return this.data.pipe(distinctUntilChanged());
}
// ...
}
和一個調用這個服務的組件來做
this.banana$ = combineLatest([
someFnToRequestANetworkObject(),
DataService.getData()
]).pipe(
map(([network, data]) => network && data.some(_data=> _data.ip === network.ip))
);
問題是每次在combineLatest
處理的 Observable combineLatest
被發出時,我都會調用Array.prototype.some()
函數。 我不想這樣做。
我怎樣才能優化這段代碼,這樣我就不會經常調用some
代碼?
關於distinctUntilChanged()
操作符需要注意的一件事是它只影響訂閱。 所以源 observable 和訂閱之間的操作符仍然在運行。 作為解決方法,您可以手動檢查排放之間的data
是否發生了變化。 嘗試以下
let oldData: any;
this.banana$ = combineLatest([
someFnToRequestANetworkObject(),
DataService.getData()
]).pipe(
map(([network, data]) => {
if (!oldData || oldData !== data) {
oldData = data;
return (network && data.some(_data=> _data.ip === network.ip));
}
return false; // <-- return what you wish when `data` hasn't changed
})
);
我認為您對distinctUntilChanged
不起作用的預感是正確的。 默認情況下,此運算符使用相等檢查來確定兩個值是否相同。 但是,如果被比較的對象不是簡單的標量值(如數字或布爾值),這(在大多數情況下)將無法正常工作。
事實證明, 您可以提供自己的比較器函數作為distinctUntilChanged
的第一個參數。 這將在“連續”元素上調用以確定新元素是否與最近的元素不同。
此比較器函數的確切定義取決於您的SomeData
類/接口的外觀,以及SomeData
居民數組與另一個相同的SomeData
。 但是,舉個例子,假設SomeData
看起來像這樣:
interface SomeData {
id: string;
name: string;
age: number;
}
並且SomeData
居民如果具有相同的id
則相同。 此外,假設SomeData
的兩個數組相同,如果它們包含完全相同的SomeData
元素。 那么我們的比較器函數可能看起來像:
function eqSomeDataArrays(sds1: SomeData[], sds2: SomeData[]): boolean {
// Two arrays of `SomeData` inhabitants are the same if...
// ...they contain the same number of elements...
return sds1.length === sds2.length
// ...which are "element-wise", the same (i.e. have the same `id`)
&& sds1.every((sd1, i) => sd1.id === sds2[i].id)
}
為了解決這個問題,你的getData
方法現在看起來像:
getData(): Observable<SomeData[]> {
return this.data.pipe(distinctUntilChanged(eqSomeDataArrays));
}
在管道中,地圖調用后,您可以使用 shareReplay(1)
this.banana$ = combineLatest([
someFnToRequestANetworkObject(),
DataService.getData()])
.pipe(
map(([network, data]) => network && data.some(_data=> _data.ip === network.ip)),
shareReplay(1)
);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.