假設存在A/B函數相互關聯,A函數每次一次正向操做,B函數必然會執行一次反向操做,A/B函數保證相關抵消。 那麼考慮如下場景:git
ABABABABABABABABABABABABABgithub
A/B函數高頻率觸發,可是最終效果都是抵消的,此時若是基於用戶交互優化,以及節約性能的考慮,能夠進行約束節流。 不改變最終的效果,可是能夠減小觸發次數。數據庫
優化效果可能以下:npm
A----------B----------A------------Bapp
遇到這種問題,機智的我嘗試寫了個函數,實現了大體效果,源碼地址:BT異步
上圖中所示,若是不作優化,基本上每一行都會執行真正的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
(若是有同窗好奇去搜,頗有可能雙函數約束節流這個名詞就是不存在,我瞎編的哈哈哈哈...)