如何解决js函数防抖、节流出现的问题
前端  /  管理员 发布于 4年前   324
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 treturn () => {let context = thislet args = argumentsif (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 timeoutreturn () => {// 在返回的函数内部保留上下文和参数let context = thislet args = argumentslet 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);
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
123 在
Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..原梓番博客 在
在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..博主 在
佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..1111 在
佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..路人 在
php中使用hyperf框架调用讯飞星火大模型实现国内版chatgpt功能示例中评论 教程很详细,如果加个前端chatgpt对话页面就完美了..Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号