如何解决js函数防抖、节流出现的问题

React中使用防抖函数和节流函数

在React事件调用时,React传递给事件处理程序是一个合成事件对象的实例。SyntheticEvent对象是通过合并得到的。 这意味着在事件回调被调用后,SyntheticEvent 对象将被重用并且所有属性都将被取消。 这是出于性能原因。 因此,您无法以异步方式访问该事件。React合成事件官方文档

所以在用防抖或节流函数封装时,异步方式访问事件对象出现问题。解决的方法如下:

方法一:调用合成事件对象的persist()方法 event.persist && event.persist() //保留对事件的引用

方法二:深拷贝事件对象 const event = e && {...e} //深拷贝事件对象

function debounce(func, wait=500) {

let timeout; // 定时器变量

return function(event){

clearTimeout(timeout); // 每次触发时先清除上一次的定时器,然后重新计时

event.persist && event.persist() //保留对事件的引用

//const event = e && {...e} //深拷贝事件对象

timeout = setTimeout(()=>{

func(event)

}, wait); // 指定 xx ms 后触发真正想进行的操作 handler

};

}

防抖debounce

防抖 Debounce 多次触发,只在最后一次触发时,执行目标函数。

函数防抖就是,延迟一段时间再执行函数,如果这段时间内又触发了该函数,则延迟重新计算。

应用场景

(1)通过监听某些事件完成对应的需求,比如:

通过监听 scroll 事件,检测滚动位置,根据滚动位置显示返回顶部按钮

通过监听 resize 事件,对某些自适应页面调整DOM的渲染(通过CSS实现的自适应不再此范围内)

通过监听 keyup 事件,监听文字输入并调用接口进行模糊匹配

(2)其他场景

表单组件输入内容验证

防止多次点击导致表单多次提交

简单实现

function debounce(fn, wait) {

let t

return () => {

let context = this

let args = arguments

if (t) clearTimeout(t)

t= setTimeout(() => {

fn.apply(context, args)

}, wait)

}

}

完整实现

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中调用方法

this.handleGetCustomerNameList = debounce(this.handleGetCustomerNameList.bind(this), 500);

节流 throttle

节流:函数间隔一段时间后才能再触发,避免某些函数触发频率过高,比如滚动条滚动事件触发的函数。

### 简单实现

function throttle (fn, wait, mustRun) {

let start = new Date()

let timeout

return () => {

// 在返回的函数内部保留上下文和参数

let context = this

let args = arguments

let current = new Date()

clearTimeout(timeout)

let remaining = current - start

// 达到了指定触发时间,触发该函数

if (remaining > mustRun) {

fn.apply(context, args)

start = current

} else {

// 否则wait时间后触发,闭包保留一个timeout实例

timeout = setTimeout(fn, wait);

}

}

}

完整实现

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中调用方法

this.handleGetCustomerNameList = throttle (this.handleGetCustomerNameList.bind(this), 500);

以上是 如何解决js函数防抖、节流出现的问题 的全部内容, 来源链接: utcz.com/z/336318.html

回到顶部