# Debounce : 使用者輸入時 , 延緩表格的檢查 ###### tags : `w3HexSchool` . `js` > 有時我們會需要在用戶輸入帳戶名稱的同時 , 確認此帳戶名稱已存在 > 來提升註冊流程的舒適感 , 可是我們不可能在用戶輸入時 , > 一直呼叫 "用戶名稱是否存在 API" , 這樣 API & 用戶 4G 的流量會過高 > 因此我們需要 "使用者輸入時 , 延緩表格的檢查" 這樣的功能 > 不過 , 這該如何實現呢 ? 🤔 > 讓我們請出今天的主角 `debounce` 函式 來幫忙吧 😘 ! - [debounce 與一般滑鼠移動的比較](http://demo.nimius.net/debounce_throttle/) ![](https://i.imgur.com/Zyx9xI7.png) > 確認上方功能是我們想要的 , 之後就來 `使用` 吧! 下載 `lodash` ``` npm i -s lodash ``` 引用 `lodash` ``` import _ from 'lodash' ``` > 剛開始使用 `debounce` 時 , 我以為直接執行就成了 , 結果... - [debounce 文件](https://lodash.com/docs/4.17.15#debounce) ![](https://i.imgur.com/AUv7NJS.png) 看 `debounce` 文件時 , 我天真的以為代入 2 個參數就可執行了 , 結果發現沒有任何反應 ```javascript= _.debounce(()=>console.log('debounce trigger'),1000) ``` console.log 後 , 才知道 `_.debounce` 會回傳 function ```javascript= const x = _.debounce(()=>console.log('debounce trigger'),1000); console.log('x=',x); ``` ![](https://i.imgur.com/bsRhFm9.png) 所以我多加 () 去執行回傳的函數 , 這次看起來好像沒問題 ? ```javascript= (_.debounce(()=>console.log('debounce trigger'),1000))(); ``` ![](https://i.imgur.com/1phkzzr.png) 當我多次執行時 , 發現他沒有延遲執行 , 發生了甚麼事情 😱 ? ![](https://i.imgur.com/56OouKn.png) > 近期找到[一篇文章](https://mropengate.blogspot.com/2017/12/dom-debounce-throttle.html) , 它分享了 `debounce` 函數的長相 , 我才瞭解說為何不能當作函數直接呼叫 , 原來每次呼叫 `debounce` 都會建一個全新的 timer ```javascript= function debounce(func, delay) { var timer = null; return function () { var context = this; var args = arguments; clearTimeout(timer); timer = setTimeout(function () { func.apply(context, args) }, delay); } } ``` 正確用法 , 應該長這樣 , 我們只能執行回傳的函式 ```javascript= const x = _.debounce(()=>console.log('debounce trigger'),1000); x(); x(); x(); ``` ![](https://i.imgur.com/5sQ6E2V.png) > 每次使用時 , 都需要在 create 階段建一個函數放到 this 中 , 感覺使用起來很不方便啊 ! ```javascript= export default { name: "Comp", create() { this.nameDebounceFn = _.debounce(()=>console.log('validate name'),1000); this.accountDebounceFn = _.debounce(()=>console.log('validate account'),1000); }, data() { return { this.nameDebounceFn: null, this.accountDebounceFn: null, } } } ``` > 讓我們做一個 getDebounceFunc 函式 , 來輔助我們使用 `debounce` 吧 ! 建立 `getDebounceFunc` ```javascript= // in debounceUtils.js const debounceMap = {}; const getDebounceFunc = (debounceId, wait = 1000) => { const tempFunc = debounceMap[`${debounceId}`]; if (tempFunc) return tempFunc; else { const newTempFunc = debounce(func => func(), wait); debounceMap[`${debounceId}`] = newTempFunc; return newTempFunc; } }; ``` 使用 `getDebounceFunc` ```javascript= // 使用說明 export default { name: "Comp", watch: { account(value) { getDebounceFunc('validateAccount')(()=>{ console.log('validate account'); }); }, name(value) { getDebounceFunc('validateName')(()=>{ console.log('validate name'); }); }, }, data() { return { account:'', name:'' } } } ``` > 包裝成 util 後 , 有幾點好處 > 1. 不用在建立 debounce 時 , 就必須決定要執行的內容 > 2. 不用將 debounce 回傳的函式暫存到 this 中 ## 結語 當初會需要使用 `debounce` 是因為 使用者輸入品號時 , 一直 request API 確認 品號是否重複 , 影響到 API 的效能 , 因此導入 `debounce` 函式使用 只是 , 當初導入時 , 沒想到 `debounce` 的使用這麼複雜 , 因此在此紀錄 , 以便下次使用 `debounce` 又踩坑 ## 參考資料 - [網頁 DOM 事件的效能優化:Debounce 和 Throttle](https://mropengate.blogspot.com/2017/12/dom-debounce-throttle.html) - [How to import lodash to Chrome console?](https://medium.com/@matt.leo/how-to-import-lodash-to-chrome-console-3e5e30b4933e)