簡體   English   中英

如何減少 amap Array.prototype.some() 調用?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM