雙函數約束節流的設計

背景

假設存在A/B函數相互關聯,A函數每次一次正向操做,B函數必然會執行一次反向操做,A/B函數保證相關抵消。 那麼考慮如下場景:git

ABABABABABABABABABABABABABgithub

目標

A/B函數高頻率觸發,可是最終效果都是抵消的,此時若是基於用戶交互優化,以及節約性能的考慮,能夠進行約束節流。 不改變最終的效果,可是能夠減小觸發次數。數據庫

優化效果可能以下:npm

A----------B----------A------------Bapp

遇到這種問題,機智的我嘗試寫了個函數,實現了大體效果,源碼地址:BT異步

database

上圖中所示,若是不作優化,基本上每一行都會執行真正的A/B函數邏輯(以/SKIP/、/DONE/標記開頭的那些,/SHOW/是爲了展現那個時間點的數據庫結果)。函數

圖中示例是以300ms進行約束節流的,優化後,圖中白色和紅色那些行即爲真正執行的A/B函數邏輯性能

實現原理

經過計數器來記錄A/B函數執行次數,同時利用時間戳和定時器,判斷A函數執行後,在節流時間內將多餘的A函數略過,同時最大控制B函數在節流時間的末尾執行。優化

count: 0, // 平衡值,最終全部A/B函數執行完後,確保count === 0
ctime: 0, // 每次執行真的A函數開始後的觸發時間
F_callTimes: 0, // A函數(不管真假)執行次數
B_callTimes: 0, // B函數(不管真假)執行次數
複製代碼

爲了確保不出錯,在定時器裏經過判斷A/B函數執行次數,始終確保兩個函數執行次數相一致。ui

timeRef.unset().set(() => {
  const delta = F_callTimes - B_callTimes;
  for (let i = 0; i <= delta; i++) {
    wrapperB(...args);  // 執行B包裹函數
  }
}, idleness);
複製代碼

有同窗看到了不管真假,確定滿臉問號。

是這樣的,真的A/B函數就是真的業務邏輯,可能會帶有各類反作用,消耗性能等。而假的A/B函數,就是替換真的A/B函數而存在的,能夠用來打印日誌等等。

優化

在開發這個BT過程當中,遇到了一個問題,若是A/B函數,傳參不一樣的話,那麼很明顯是用來執行不一樣操做的,此時須要進行分類約束節流。這個簡單能夠經過一個對象記錄分類。

function generateRecord(type) {
  BTRecrod[type] = {
    count: 0,
    ctime: 0,
    F_callTimes: 0,
    B_callTimes: 0,
    timeRef: Object.assign({}, timeout)
  };
}
複製代碼

而type就是分類的依據,那怎麼生成呢?經過參數拼接一下,就獲得不一樣的type。這裏簡單隻作了原始值類型的處理,若是是對象的話,能夠深度遍歷一下去計算生成不同的type~

export function generateType(...args) {
  return ["BT"].concat(args).join("_");
}
複製代碼

至此,還有一個問題沒有處理,若是A/B函數是異步的怎麼辦?可能須要等待A/B函數異步返回成功的時候,才能算作執行成功...

使用

最終調用效果以下:

import { BT } from "binary-throttle";
 
function forward() {
  // @TODO
}
 
function backward() {
  // @TODO
}
 
const [X, Y] = BT(forward, backward, {
  // idleness: 300,
  // fallbackF: () => console.log('X was ignore this time.'),
  // fallbackB: () => console.log('Y was ignore this time.')
});
複製代碼

接下來不管forward,backward函數交換調用多麼頻繁,通過BT的約束節流處理後,都只會大大減小調用次數,可是最終結果仍是一致的。

小結

這個函數我已經發了個包名叫binary-throttle,仍是不推薦你們使用(由於),寫出來純粹是交個朋友😏,給你們提供點思路,順便本身也記錄一下~

這種場景可能比較少見,不過不影響你們感興趣能夠戳戳: BT

(若是有同窗好奇去搜,頗有可能雙函數約束節流這個名詞就是不存在,我瞎編的哈哈哈哈...)

相關文章
相關標籤/搜索