JS奇淫巧技:防抖函数与节流函数
2017-12-06 09:02
561 查看
应用场景
实际工作中,我们经常性的会通过监听某些事件完成对应的需求,比如:
通过监听 scroll 事件,检测滚动位置,根据滚动位置显示返回顶部按钮
通过监听 resize 事件,对某些自适应页面调整DOM的渲染(通过CSS实现的自适应不再此范围内)
通过监听 keyup 事件,监听文字输入并调用接口进行模糊匹配
...
常规实现,以监听 scroll 事件为例
我们先来看一下scroll事件的触发频率
效果如下:
从效果上,我们可以看到,在页面滚动的时候,会在短时间内触发多次绑定事件。
我们知道DOM操作是很耗费性能的,如果在监听中,做了一些DOM操作,那无疑会给浏览器造成大量性能损失。
下面我们进入主题,一起来探究,如何对此进行优化。
函数防抖
定义:多次触发事件后,事件处理函数只执行一次,并且是在触发操作结束时执行。
原理:对处理函数进行延时操作,若设定的延时到来之前,再次触发事件,则清除上一次的延时操作定时器,重新定时。
scroll 的一个简单例子
效果如下:滚动结束触发事件
防抖函数的封装使用
函数防抖的适用性:
通过上面的例子,我们知道我们可以通过函数防抖,解决了多次触发事件时的性能问题。
比如,我们在监听滚动条位置,控制是否显示返回顶部按钮时,就可以将防抖函数应用其中。
但依然有些功能并不适用:
当我们做图片懒加载(lazyload)时,需要通过滚动位置,实时显示图片时,如果使用防抖函数,懒加载(lazyload)函数将会不断被延时,
只有停下来的时候才会被执行,对于这种需要实时触发事件的情况,就显得不是很友好了。
下面开始介绍函数节流,通过设定时间片,控制事件函数间断性的触发。
函数节流
定义:触发函数事件后,短时间间隔内无法连续调用,只有上一次函数执行后,过了规定的时间间隔,才能进行下一次的函数调用。
原理:对处理函数进行延时操作,若设定的延时到来之前,再次触发事件,则清除上一次的延时操作定时器,重新定时。
scroll 的一个简单例子
效果如下:每隔500毫秒触发一次事件
防抖函数的封装使用
文中如果出现错误,希望小伙伴们可以谅解,更希望可以给予指正
实际工作中,我们经常性的会通过监听某些事件完成对应的需求,比如:
通过监听 scroll 事件,检测滚动位置,根据滚动位置显示返回顶部按钮
通过监听 resize 事件,对某些自适应页面调整DOM的渲染(通过CSS实现的自适应不再此范围内)
通过监听 keyup 事件,监听文字输入并调用接口进行模糊匹配
...
常规实现,以监听 scroll 事件为例
我们先来看一下scroll事件的触发频率
window.onscroll = function () { //滚动条位置 let scrollTop = document.body.scrollTop || document.documentElement.scrollTop; console.log('滚动条位置:' + scrollTop); }
效果如下:
从效果上,我们可以看到,在页面滚动的时候,会在短时间内触发多次绑定事件。
我们知道DOM操作是很耗费性能的,如果在监听中,做了一些DOM操作,那无疑会给浏览器造成大量性能损失。
下面我们进入主题,一起来探究,如何对此进行优化。
函数防抖
定义:多次触发事件后,事件处理函数只执行一次,并且是在触发操作结束时执行。
原理:对处理函数进行延时操作,若设定的延时到来之前,再次触发事件,则清除上一次的延时操作定时器,重新定时。
scroll 的一个简单例子
let timer; window.onscroll = function () { if(timer){ clearTimeout(timer) } timer = setTimeout(function () { //滚动条位置 let scrollTop = document.body.scrollTop || document.documentElement.scrollTop; console.log('滚动条位置:' + scrollTop); timer = undefined; },200) }
效果如下:滚动结束触发事件
防抖函数的封装使用
/** * 防抖函数 * @param method 事件触发的操作 * @param delay 多少毫秒内连续触发事件,不会执行 * @returns {Function} */ function debounce(method,delay) { let timer = null; return function () { let self = this, args = arguments; timer && clearTimeout(timer); timer = setTimeout(function () { method.apply(self,args); },delay); } }
window.onscroll = debounce(function () { let scrollTop = document.body.scrollTop || document.documentElement.scrollTop; console.log('滚动条位置:' + scrollTop); },200)
函数防抖的适用性:
通过上面的例子,我们知道我们可以通过函数防抖,解决了多次触发事件时的性能问题。
比如,我们在监听滚动条位置,控制是否显示返回顶部按钮时,就可以将防抖函数应用其中。
但依然有些功能并不适用:
当我们做图片懒加载(lazyload)时,需要通过滚动位置,实时显示图片时,如果使用防抖函数,懒加载(lazyload)函数将会不断被延时,
只有停下来的时候才会被执行,对于这种需要实时触发事件的情况,就显得不是很友好了。
下面开始介绍函数节流,通过设定时间片,控制事件函数间断性的触发。
函数节流
定义:触发函数事件后,短时间间隔内无法连续调用,只有上一次函数执行后,过了规定的时间间隔,才能进行下一次的函数调用。
原理:对处理函数进行延时操作,若设定的延时到来之前,再次触发事件,则清除上一次的延时操作定时器,重新定时。
scroll 的一个简单例子
let startTime = Date.now(); //开始时间 let time = 500; //间隔时间 let timer; window.onscroll = function throttle(){ let currentTime = Date.now(); if(currentTime - startTime >= time){ let scrollTop = document.body.scrollTop || document.documentElement.scrollTop; console.log('滚动条位置:' + scrollTop); startTime = currentTime; }else{ clearTimeout(timer); timer = setTimeout(function () { throttle() }, 50); } }
效果如下:每隔500毫秒触发一次事件
防抖函数的封装使用
/** * 节流函数 * @param method 事件触发的操作 * @param mustRunDelay 间隔多少毫秒需要触发一次事件 */ function throttle(method, mustRunDelay) { let timer, args = arguments, start; return function loop() { let self = this; let now = Date.now(); if(!start){ start = now; } if(timer){ clearTimeout(timer); } if(now - start >= mustRunDelay){ method.apply(self, args); start = now; }else { timer = setTimeout(function () { loop.apply(self, args); }, 50); } } } window.onscroll = throttle(function () { let scrollTop = document.body.scrollTop || document.documentElement.scrollTop; console.log('滚动条位置:' + scrollTop); },800)
文中如果出现错误,希望小伙伴们可以谅解,更希望可以给予指正
相关文章推荐
- js函数防抖、节流实现
- js函数节流和防抖
- js中连续触发事件的稀释方法(函数节流、函数防抖、标识变量)
- JS 函数节流和去抖
- js的函数节流(throttle)
- js节流函数高级版
- JavaScript小知识点(二):函数防抖和节流
- 节流函数和防抖函数学习
- 节流或防抖:控制函数的执行
- 函数节流 + 函数防抖
- js节流函数和js防止重复提交的N种方法
- 详细分析JS函数去抖和节流
- 函数节流与函数防抖
- 谈谈JS中的函数节流
- JS学习--函数防抖(debounce)
- 事件委托、函数节流及防抖
- JS学习 函数节流(throttle)
- js 节流函数 throttle
- JS函数节流代码实现
- 页面优化之高性能函数防抖与节流