閉包與鏈式設計的使用示例

最近遇到了個按需請求數據的需求,很是適合用於講解閉包與鏈式設計的例子,故來分享一下思路。git

大體需求以下: 目前有個 list, list 中每項 item 都是可展開的摺疊項。當展開某個摺疊項時,須要根據 item 的 code 另外去取 name 的映射。考慮到列表的數據量很是大,且一次性查詢過多 code 時,接口的查詢效率會明顯下降,故採用按需請求映射的方案。github

屏蔽與本例無關的屬性,瘦身後的 list 數據結構大體以下:typescript

interface DataType {
  code: string;
  paymentTransaction: string[];
}

type ListType = DataType[];

咱們知道大型企業中的數據會比較複雜,比較常見的一種狀況是數據中有一個 id 或 code 是用於跟另外一個數據項相關聯的。學習過數據庫的同窗很容易就聯想到了外鍵這個概念。數據庫

如今咱們就要取出這些 code 發送給服務端去查詢。考慮到 code 可能會有重複,所以能夠將 codes 存入 Set 中,利用 Set 的特性去重。除此以外,爲了使 name 映射能夠被複用,每次從接口返回的 name 映射將會被緩存起來。若下次再觸發事件時有對應的 key,便再也不查詢。數組

咱們能夠將這段邏輯抽離出來做爲一個依賴收集的函數:緩存

const mapping = new Map();

function collectionCodes(initCodes?: string[] | Set<string>) {
  const codes = new Set<string>(initCodes)

  return {
    append(code: string) {
      if (!mapping.has(code)) {
        codes.add(code);
      }

      return this;
    },
    empty() {
      return !codes.size;
    },
    value() {
      return codes;
    },
  }
}

collectionCodes 函數是用於收集 codes。它內部利用了閉包的特性將 codes 緩存了起來,而且在添加新的 code 以前會判斷 code 在 local 的映射中是否已經存在。append 返回的 this 是經典的鏈式調用設計,容許屢次鏈式添加。當本次依賴收集結束後,調用 value 方法獲取最終的 codes。數據結構

能夠寫一些簡單的 mock 數據進行嘗試:閉包

function handleNameMapping(data: DataType) {
  const codes = collectionCodes()
    .append(data.code)
    .append('code-append-1')
    .append('code-append-1')
    .append('code-append-2');

  data.paymentTransaction.forEach(code => codes.append(code));

  if (codes.empty()) {
    console.log('can get values from existing mapping.')
    return;
  }

  // 若是請求的數據須要轉爲數組,能夠 Array.from 進行轉換
  const list = Array.from(codes.value());
  console.log('fetch data before, codes --> ', list);

  // mock 獲取數據後拿到 name mapping 後,存入 mapping 中的行爲.
  // 注意,Set 類型也能夠用 forEach 方法,不必定得轉爲數組才能夠操做
  list.forEach(code => mapping.set(code, `random-name-${Math.random()}`))
}

const mockItemData = {
  code: 'code-main',
  paymentTransaction: [
    'code-payment-4',
    'code-payment-1',
    'code-payment-2',
    'code-payment-1',
    'code-payment-3',
  ]
}

handleNameMapping(mockItemData);
// fetch data before, codes -->  (7) ["code-main", "code-append-1", "code-append-2", "code-payment-4", "code-payment-1", "code-payment-2", "code-payment-3"]

handleNameMapping(mockItemData);
// can get values from existing mapping.

handleNameMapping 在發起請求前會作 code 收集,若本次收集中沒有須要 fetch 的 code,那就避免發送無用的 HTTP 請求,從而達到了優化的目的。app

最終示例的 TS 代碼以下。若想直接在控制檯嘗試效果的話,能夠經過 ts 官網中的 Playground 編譯爲可直接運行的 js 代碼:dom

interface DataType {
  code: string;
  paymentTransaction: string[];
}

const mapping = new Map();

function collectionCodes(initCodes?: string[] | Set<string>) {
  const codes = new Set<string>(initCodes);

  return {
    append(code: string) {
      if (!mapping.has(code)) {
        codes.add(code);
      }

      return this;
    },
    empty() {
      return !codes.size;
    },
    value() {
      return codes;
    },
  };
}

function handleNameMapping(data: DataType) {
  const codes = collectionCodes()
    .append(data.code)
    .append('code-append-1')
    .append('code-append-1')
    .append('code-append-2');

  data.paymentTransaction.forEach((code) => codes.append(code));

  if (codes.empty()) {
    console.log('can get values from existing mapping.');
    return;
  }

  // 若是請求的數據須要轉爲數組,能夠 Array.from 進行轉換
  const list = Array.from(codes.value());
  console.log('fetch data before, codes --> ', list);

  // mock 獲取數據後拿到 name mapping 後,存入 mapping 中的行爲.
  // 注意,Set 類型也能夠用 forEach 方法,不必定得轉爲數組才能夠操做
  list.forEach(code => mapping.set(code, `random-name-${Math.random()}`))
}

const mockItemData = {
  code: 'code-main',
  paymentTransaction: [
    'code-payment-4',
    'code-payment-1',
    'code-payment-2',
    'code-payment-1',
    'code-payment-3',
  ],
};

handleNameMapping(mockItemData);
// fetch data before, codes -->  (7) ["code-main", "code-append-1", "code-append-2", "code-payment-4", "code-payment-1", "code-payment-2", "code-payment-3"]

handleNameMapping(mockItemData);
// can get values from existing mapping.

本例的分析就到此結束了,雖然在本例中鏈式調用沒有充分展現出本身的優點,但也能夠做爲一個設計思路用於參考。


原文出自: 閉包與鏈式設計的使用示例 | Anran758's blog

相關文章
相關標籤/搜索