如何解決js函數(shù)防抖、節(jié)流出現(xiàn)的問題
React中使用防抖函數(shù)和節(jié)流函數(shù)
在React事件調(diào)用時(shí),React傳遞給事件處理程序是一個(gè)合成事件對象的實(shí)例。SyntheticEvent對象是通過合并得到的。 這意味著在事件回調(diào)被調(diào)用后,SyntheticEvent 對象將被重用并且所有屬性都將被取消。 這是出于性能原因。 因此,您無法以異步方式訪問該事件。React合成事件官方文檔
所以在用防抖或節(jié)流函數(shù)封裝時(shí),異步方式訪問事件對象出現(xiàn)問題。解決的方法如下:
方法一:調(diào)用合成事件對象的persist()方法 event.persist && event.persist() //保留對事件的引用
方法二:深拷貝事件對象 const event = e && {...e} //深拷貝事件對象
function debounce(func, wait=500) { let timeout; // 定時(shí)器變量 return function(event){ clearTimeout(timeout); // 每次觸發(fā)時(shí)先清除上一次的定時(shí)器,然后重新計(jì)時(shí) event.persist && event.persist() //保留對事件的引用 //const event = e && {...e} //深拷貝事件對象 timeout = setTimeout(()=>{ func(event) }, wait); // 指定 xx ms 后觸發(fā)真正想進(jìn)行的操作 handler }; }
防抖debounce
防抖 Debounce 多次觸發(fā),只在最后一次觸發(fā)時(shí),執(zhí)行目標(biāo)函數(shù)。
函數(shù)防抖就是,延遲一段時(shí)間再執(zhí)行函數(shù),如果這段時(shí)間內(nèi)又觸發(fā)了該函數(shù),則延遲重新計(jì)算。
應(yīng)用場景
(1)通過監(jiān)聽某些事件完成對應(yīng)的需求,比如:
通過監(jiān)聽 scroll 事件,檢測滾動位置,根據(jù)滾動位置顯示返回頂部按鈕
通過監(jiān)聽 resize 事件,對某些自適應(yīng)頁面調(diào)整DOM的渲染(通過CSS實(shí)現(xiàn)的自適應(yīng)不再此范圍內(nèi))
通過監(jiān)聽 keyup 事件,監(jiān)聽文字輸入并調(diào)用接口進(jìn)行模糊匹配
(2)其他場景
表單組件輸入內(nèi)容驗(yàn)證
防止多次點(diǎn)擊導(dǎo)致表單多次提交
簡單實(shí)現(xiàn)
function debounce(fn, wait) { let t return () => { let context = this let args = arguments if (t) clearTimeout(t) t= setTimeout(() => { fn.apply(context, args) }, wait) } }
完整實(shí)現(xiàn)
function debounce(func, wait, immediate) { let time; let debounced = function() { let context = this; if(time) clearTimeout(time); if(immediate) { let callNow = !time; if(callNow) func.apply(context, arguments); time = setTimeout( ()=>{time = null} //見注解 , wait) } else { time = setTimeout( ()=>{func.apply(context, arguments)} , wait) } }; debounced.cancel = function() { clearTimeout(time); time = null }; return debounced } // underscore.js debounce // // Returns a function, that, as long as it continues to be invoked, will not // be triggered. The function will be called after it stops being called for // N milliseconds. If `immediate` is passed, trigger the function on the // leading edge, instead of the trailing. _.debounce = function(func, wait, immediate) { var timeout, args, context, timestamp, result; // 處理時(shí)間 var later = function() { var last = _.now() - timestamp; if (last < wait && last >= 0) { timeout = setTimeout(later, wait - last); // 10ms 6ms 4ms } else { timeout = null; if (!immediate) { result = func.apply(context, args); if (!timeout) context = args = null; } } };
react中調(diào)用方法
this.handleGetCustomerNameList = debounce(this.handleGetCustomerNameList.bind(this), 500);
節(jié)流 throttle
節(jié)流:函數(shù)間隔一段時(shí)間后才能再觸發(fā),避免某些函數(shù)觸發(fā)頻率過高,比如滾動條滾動事件觸發(fā)的函數(shù)。
### 簡單實(shí)現(xiàn) function throttle (fn, wait, mustRun) { let start = new Date() let timeout return () => { // 在返回的函數(shù)內(nèi)部保留上下文和參數(shù) let context = this let args = arguments let current = new Date() clearTimeout(timeout) let remaining = current - start // 達(dá)到了指定觸發(fā)時(shí)間,觸發(fā)該函數(shù) if (remaining > mustRun) { fn.apply(context, args) start = current } else { // 否則wait時(shí)間后觸發(fā),閉包保留一個(gè)timeout實(shí)例 timeout = setTimeout(fn, wait); } } }
完整實(shí)現(xiàn)
function throttle(func, wait, options) { let time, context, args, result; let previous = 0; if (!options) options = {}; let later = function () { previous = options.leading === false ? 0 : new Date().getTime(); time = null; func.apply(context, args); if (!time) context = args = null; }; let throttled = function () { let now = new Date().getTime(); if (!previous && options.leading === false) previous = now; let remaining = wait - (now - previous); context = this; args = arguments; if (remaining <= 0 || remaining > wait) { if (time) { clearTimeout(time); time = null; } previous = now; func.apply(context, args); if (!time) context = args = null; } else if (!time && options.trailing !== false) { time = setTimeout(later, remaining); } }; return throttled; } // underscore.js throttle // Returns a function, that, when invoked, will only be triggered at most once // during a given window of time. Normally, the throttled function will run // as much as it can, without ever going more than once per `wait` duration; // but if you'd like to disable the execution on the leading edge, pass // `{leading: false}`. To disable execution on the trailing edge, ditto. _.throttle = function(func, wait, options) { var context, args, result; var timeout = null; var previous = 0; if (!options) options = {}; var later = function() { previous = options.leading === false ? 0 : _.now(); timeout = null; result = func.apply(context, args); if (!timeout) context = args = null; }; return function() { var now = _.now(); if (!previous && options.leading === false) previous = now; var remaining = wait - (now - previous); context = this; args = arguments; if (remaining <= 0 || remaining > wait) { if (timeout) { clearTimeout(timeout); timeout = null; } previous = now; result = func.apply(context, args); if (!timeout) context = args = null; } else if (!timeout && options.trailing !== false) { timeout = setTimeout(later, remaining); } return result; }; };
react中調(diào)用方法
this.handleGetCustomerNameList = throttle (this.handleGetCustomerNameList.bind(this), 500);
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- JavaScript函數(shù)節(jié)流和函數(shù)防抖之間的區(qū)別
- JS函數(shù)節(jié)流和函數(shù)防抖問題分析
- JS函數(shù)節(jié)流和防抖之間的區(qū)分和實(shí)現(xiàn)詳解
- js防抖函數(shù)和節(jié)流函數(shù)使用場景和實(shí)現(xiàn)區(qū)別示例分析
- javascript函數(shù)的節(jié)流[throttle]與防抖[debounce]
- 如何在面試中手寫出javascript節(jié)流和防抖函數(shù)
- 淺談JS函數(shù)節(jié)流防抖
- Javascript節(jié)流函數(shù)throttle和防抖函數(shù)debounce
- 淺談JavaScript節(jié)流和防抖函數(shù)
- JS防抖節(jié)流函數(shù)的實(shí)現(xiàn)與使用場景
相關(guān)文章
javascript中使用正則表達(dá)式清理table樣式的代碼
本文給大家講解的是使用javascript實(shí)現(xiàn)去除多余的TABLE的樣式,主要通過結(jié)合正則表達(dá)式來實(shí)現(xiàn),非常的簡單實(shí)用,有需要的小伙伴可以參考下。2015-07-07javascript實(shí)現(xiàn)C語言經(jīng)典程序題
這篇文章主要介紹了javascript實(shí)現(xiàn)C語言經(jīng)典程序題的解題思路,感興趣的小伙伴們可以參考一下2015-11-11JS實(shí)現(xiàn)可自定義大小,可雙擊關(guān)閉的彈出層效果
這篇文章主要介紹了JS實(shí)現(xiàn)可自定義大小,可雙擊關(guān)閉的彈出層效果,涉及JavaScript定時(shí)函數(shù)及頁面元素動態(tài)操作的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-10-10javascript自定義startWith()和endWith()的兩種方法
js中自定義startWith()和endWith()方法有兩種,在本文將為大家詳細(xì)介紹下,感興趣的朋友不要錯(cuò)過2013-11-11關(guān)于onScroll事件在IE6下每次滾動觸發(fā)三次bug說明
今天測試發(fā)現(xiàn)IE6下用window.onscroll,每次滾動時(shí)會觸發(fā)3次,而火狐、IE7沒此問題,應(yīng)該是IE6的一個(gè)BUG2011-09-09js實(shí)現(xiàn)內(nèi)置計(jì)時(shí)器
這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)內(nèi)置計(jì)時(shí)器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-12-12javaScript讓文本框內(nèi)的最后一個(gè)文字的后面獲得焦點(diǎn)實(shí)現(xiàn)代碼
讓文本框內(nèi)的最后一個(gè)文字的后面獲得焦點(diǎn),在應(yīng)用中很常見,接下來提供解決方案,按興趣的朋友可以了解下2013-01-01