如何解決js函數(shù)防抖、節(jié)流出現(xiàn)的問題
React中使用防抖函數(shù)和節(jié)流函數(shù)
在React事件調(diào)用時,React傳遞給事件處理程序是一個合成事件對象的實例。SyntheticEvent對象是通過合并得到的。 這意味著在事件回調(diào)被調(diào)用后,SyntheticEvent 對象將被重用并且所有屬性都將被取消。 這是出于性能原因。 因此,您無法以異步方式訪問該事件。React合成事件官方文檔
所以在用防抖或節(jié)流函數(shù)封裝時,異步方式訪問事件對象出現(xiàn)問題。解決的方法如下:
方法一:調(diào)用合成事件對象的persist()方法 event.persist && event.persist() //保留對事件的引用
方法二:深拷貝事件對象 const event = e && {...e} //深拷貝事件對象
function debounce(func, wait=500) {
let timeout; // 定時器變量
return function(event){
clearTimeout(timeout); // 每次觸發(fā)時先清除上一次的定時器,然后重新計時
event.persist && event.persist() //保留對事件的引用
//const event = e && {...e} //深拷貝事件對象
timeout = setTimeout(()=>{
func(event)
}, wait); // 指定 xx ms 后觸發(fā)真正想進(jìn)行的操作 handler
};
}
防抖debounce
防抖 Debounce 多次觸發(fā),只在最后一次觸發(fā)時,執(zhí)行目標(biāo)函數(shù)。
函數(shù)防抖就是,延遲一段時間再執(zhí)行函數(shù),如果這段時間內(nèi)又觸發(fā)了該函數(shù),則延遲重新計算。
應(yīng)用場景
(1)通過監(jiān)聽某些事件完成對應(yīng)的需求,比如:
通過監(jiān)聽 scroll 事件,檢測滾動位置,根據(jù)滾動位置顯示返回頂部按鈕
通過監(jiān)聽 resize 事件,對某些自適應(yīng)頁面調(diào)整DOM的渲染(通過CSS實現(xiàn)的自適應(yīng)不再此范圍內(nèi))
通過監(jiān)聽 keyup 事件,監(jiān)聽文字輸入并調(diào)用接口進(jìn)行模糊匹配
(2)其他場景
表單組件輸入內(nèi)容驗證
防止多次點擊導(dǎo)致表單多次提交
簡單實現(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)
}
}
完整實現(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;
// 處理時間
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ù)間隔一段時間后才能再觸發(fā),避免某些函數(shù)觸發(fā)頻率過高,比如滾動條滾動事件觸發(fā)的函數(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ā)時間,觸發(fā)該函數(shù)
if (remaining > mustRun) {
fn.apply(context, args)
start = current
} else {
// 否則wait時間后觸發(fā),閉包保留一個timeout實例
timeout = setTimeout(fn, wait);
}
}
}
完整實現(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ū)分和實現(xiàn)詳解
- js防抖函數(shù)和節(jié)流函數(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ù)的實現(xiàn)與使用場景
相關(guān)文章
JS實現(xiàn)鼠標(biāo)經(jīng)過好友列表中的好友頭像時顯示資料卡的效果
需求為當(dāng)用戶鼠標(biāo)經(jīng)過好友列表中好友頭像時,顯示該好友的基本資料,其實也就是類似QQ客戶端的那種功能,下面是具體的實現(xiàn)思路及過程2014-07-07
JavaScript面向?qū)ο笾w會[總結(jié)]
看過很多JavaScript書,對JavaScript的面向?qū)ο笾v的都比較深入,但是并沒有做到深入淺出,總結(jié)了我做的一些JavaScript程序的經(jīng)驗,以簡潔明了的文字使大家明白JavaScript面向?qū)ο蟮膶崿F(xiàn)。2008-11-11
javascript學(xué)習(xí)總結(jié)之js使用技巧
本篇文章給大家分享javascript學(xué)習(xí)總結(jié)之js使用技巧,都是精華喔~小伙伴快來學(xué)習(xí)吧。2015-09-09

