雙閾值對抗資料抖動

塵鑰發表於2016-06-13

今天我想分享一下我在近期有關閾值的一些技巧,因為筆者是一名前端開發,因此下面的demo筆者使用js編寫,但是這篇文章中的技巧是一種思想並不限於js。

我們在寫程式的時候經常會發現這樣一種情況:我們需要根據某一個變數的值屬於哪個區間來控制分支的走向,比如下面的程式碼:

上面的程式碼邏輯很簡單,當num大於100時,執行taskA函式,反之執行taskB函式(假設taskA、taskB內部實現都有防止連續執行的處理)。對於大多數的場景,這樣的實現是足以滿足判斷的。但是單元測試通過不代表這個模組可以在工程中的任何場景使用。

    

試想這樣一種情況:我的頁面上有一個DOM元素,taskA()負責將內容修改為“123456”,taskB()負責將內容修改為“654321”。到目前為止上面的程式碼都可以正常執行,但是接下來就是在什麼場合呼叫changeText()了。比如這裡有一個水位監測系統,水位高於100cm時執行任務A(可能是紅燈亮)反之執行任務B(可能是路燈亮),水位剛好為100 左右時,隨著風浪水位不斷在閾值兩邊變化,taskA和taskB即使有防止連續執行的處理,也會交替執行紅燈路燈來回變化不斷的閃爍。兩個任務就會被頻繁改寫。我模擬的是一個抽象的例子,在開發中比如滑鼠移動、滑鼠滾輪、長連線、input事件等等場合都有可能遇到頻繁呼叫+閾值判斷的情形。那麼我們如何防止頻繁經過臨界點,造成的效能損耗和不好的使用者體驗呢。

接下來我將介紹雙閾值的方式。用在這個例子中使水位在100 這個臨界值變動的時候加入方向性,簡單來說從小於100 到超過100的時候綠燈滅、紅燈亮(開始警告);但是水位從高於100 到小於100時,並不馬上紅燈滅、綠燈亮。而是將從上到下的閾值另設定為95(假定風浪造成的資料抖動為5cm),來保證在警報狀態下,水位由高到低變化時,直到水位降到95cm時才解除警報(綠燈亮、紅燈滅)。這樣就在不同的兩個狀態下擁有了各自的閾值。如下圖:

如果用程式碼該怎麼實現呢?既然兩個閾值的使用依賴於當前所處的狀態。那麼我們就要“記錄”狀態,最簡單的方法是由原有的一個引數增加一個狀態引數:

單元測試:

這只是對雙閾值概念的初級實現,我們不應該每次傳遞狀態值,狀態的記錄應該交給函式自身記錄,每次的狀態依賴上一次返回的結果。我們可以通過閉包來寫一個雙閾值函式的生成器:

呼叫:

     

總結:

這樣我們就完成了一個雙閾值的函式,我們使用這樣的函式來防止位於臨界值的資料抖動。當然感興趣的同學可以擴充套件為多級的判斷函式。

相關文章