NIUCLOUD是一款SaaS管理后台框架多应用插件+云编译。上千名开发者、服务商正在积极拥抱开发者生态。欢迎开发者们免费入驻。一起助力发展! 广告
### 函数节流(throttle) > 节流的意思是让函数有节制地执行,而不是毫无节制的触发一次就执行一次。什么叫有节制呢?就是在一段时间内,只执行一次。 > > 规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效。 抓取一个关键的点:就是执行的时机。要做到控制执行的时机,我们可以通过**「一个开关」**,与定时器setTimeout结合完成。 ~~~ function throttle(fn, delay) { let flag = true, timer = null; return function (...args) { let context = this; if (!flag) return; flag = false; clearTimeout(timer) timer = setTimeout(() => { fn.apply(context, args); flag = true; }, delay); }; }; ~~~ ``` // fn 是需要执行的函数 // wait 是时间间隔 const throttle = (fn, wait = 50) => { // 上一次执行 fn 的时间 let previous = 0 // 将 throttle 处理结果当作函数返回 return function(...args) { // 获取当前时间,转换成时间戳,单位毫秒 let now = +new Date() // 将当前时间和上一次执行函数的时间进行对比 // 大于等待时间就把 previous 设置为当前时间并执行函数 fn if (now - previous > wait) { previous = now fn.apply(this, args) } } } // DEMO // 执行 throttle 函数返回新函数 const betterFn = throttle(() => console.log('fn 函数执行了'), 1000) // 每 10 毫秒执行一次 betterFn 函数,但是只有时间差大于 1000 时才会执行 fn setInterval(betterFn, 10) ``` ### 函数防抖(debounce) > 在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。 核心思想:每次事件触发都会删除原有定时器,建立新的定时器。通俗意思就是反复触发函数,只认最后一次,从最后一次开始计时。 代码: ~~~ function debounce(fn, delay) { let timer = null return function (...args) { let context = this if(timer) clearTimeout(timer) timer = setTimeout(function() { fn.apply(context, args) },delay) } } ~~~ ### 如何使用 debounce 和 throttle 以及常见的坑 自己造一个 debounce / throttle 的轮子看起来多么诱人,或者随便找个博文复制过来。**「我是建议直接使用 underscore 或 Lodash」** 。如果仅需要 `_.debounce` 和 `_.throttle` 方法,可以使用 Lodash 的自定义构建工具,生成一个 2KB 的压缩库。使用以下的简单命令即可: ~~~ npm i -g lodash-cli npm i -g lodash-clilodash-cli include=debounce,throttle ~~~ 常见的坑是,不止一次地调用 `_.debounce` 方法: ~~~ // 错误 $(window).on('scroll', function() { _.debounce(doSomething, 300); }); // 正确 $(window).on('scroll', _.debounce(doSomething, 200)); ~~~ debounce 方法保存到一个变量以后,就可以用它的私有方法 `debounced_version.cancel()`,lodash 和 underscore.js 都有效。 ~~~ let debounced_version = _.debounce(doSomething, 200); $(window).on('scroll', debounced_version); // 如果需要的话debounced_version.cancel(); ~~~ ### 适合应用场景 防抖 * search搜索,用户不断输入值时,用防抖来节约Ajax请求,也就是输入框事件。 * window触发resize时,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次 节流 * 鼠标的点击事件,比如mousedown只触发一次 * 监听滚动事件,比如是否滑到底部自动加载更多,用throttle判断 * 比如游戏中发射子弹的频率(1秒发射一颗)