函数防抖和函数分流


函数防抖和函数分流 - wudipmd - 博客园 var currentBlogApp = 'woodyblog', cb_enable_mathjax=false;var isLogined=false;

函数防抖和函数分流

应用场景

我们经常需要监听滚动条滚动或者鼠标的移动,但浏览器触发这类事件的频率非常高,可能在10几毫秒就触发一次,如果我们处理事件的函数需要操作大范围的DOM,这对于浏览器的性能是个考验,可能像chrome浏览器这样优秀的浏览器会好一点,但放到老版本的IE下,就可能发生卡顿现象。有的时候,我们只需要处理函数执行一次,比如文本输入验证,执行多次处理函数反而没有必要。

所以我们得想个办法,减少DOM操作的频度,也就是说稀释处理函数的执行频率,解决方法就是函数防抖和函数分流。函数防抖表示只执行一次处理函数,函数分流指降低处理函数的执行频率,下面是具体解释。

函数防抖

函数防抖指的是多次触发事件后,事件处理函数只执行一次,而且是在事件触发操作停止的时候。具体的思路就是延迟处理函数,如果设定的时间到来之前,又一次触发了事件,就清楚上一次的定时器,具体代码实现如下。

var obj = document.getElementById('handle');
/**
 * 事件触发的操作
 */
function myFun() {
    console.log('throttleV1');
}
/**
 * 不封装的方法
 */
obj.onmousemove = function () {
    clearTimeout(myFun.timer);
    myFun.timer = setTimeout(myFun,50);
}

这里有一个保存timer的技巧,如果不保存timer,那么执行完事件处理函数后,timer将被销毁,我们也就无法再清楚定时器了,所以需要保存这个变量,即使它所在的函数作用域对应的函数已经执行完了。这里用到的技巧是把timer设置为外部函数的属性,这样就不会被销毁了。
我们还可以对这个方法进行封装。

/**
 * 封装的方法之帮顶函数
 * @param method
 * @param delay
 * @param context
 */
function debounce(method, delay, context) {
    clearTimeout(method.timer);
    method.timer = setTimeout(function () {
        method.call(context);
    },delay);
}
obj.onmousemove = function () {
    debounce(myFun,50);
};

这里涉及到了保存timer的技巧,总共有两个方法。

设置为某个全局变量的属性,例如绑定到某个全局函数上,问题是如果传入了method是个匿名函数,绑定的timer就找不到了,所以这个方法有bug。 闭包 闭包的经典应用就是保留变量,下面是代码实现。
```
/** 封装的方法之闭包 闭包 如果想让一个函数执行完后,函数内的某个变量(timer)仍旧保留,就可以使用闭包 把要保存的变量在父作用域声明,其他的语句放到子作用域里,并且作为一个function返回

所以闭包可以理解为分离变量
*/
function debounce(method,delay) {
var timer=null;
return function () {
var context = this, args = arguments;
clearTimeout(timer);
timer = setTimeout(function () {
method.apply(context,args);
},delay);
}
}
obj.onmousemove = debounce(myFun,50);

##函数分流
函数分流的思想就是计时,上面的代码是只有在操作结束后才执行,只需要在上面的代码上加一个计时判断,如果操作了设定的时间,就执行一次处理函数,就达到了分流的效果。
/** 函数节流throttle @param 事件触发的操作 @param 延迟执行函数的时间 @param 超过多长时间必须执行一次函数

@returns {Function}
*/
function throttle(method, delay, mustRunDelay) {
var timer = null, args = arguments;
var start = 0, now = 0;
return function () {
var context = this;
now= Date.now();
if(!start){
start = now;
}
if(now - start >= mustRunDelay){
method.apply(context, args);
start = Date.now();
}else {
clearTimeout(timer);
timer = setTimeout(function () {
method.apply(context, args);
}, delay);
}

}
}
obj.onmousemove = throttle(myFun, 50, 500);
```

总结

函数防抖和函数分流的思想都是通过定时器控制函数的执行频率。

参考目录

http://www.alloyteam.com/2012/11/javascript-throttle/
http://web.jobbole.com/88306/
https://github.com/hanzichi/underscore-analysis/issues/21
https://github.com/hanzichi/underscore-analysis/issues/22


posted on 2016-12-30 22:25 wudipmd 阅读(...) 评论(...) 编辑 收藏

markdown_highlight();var allowComments=true,cb_blogId=290172,cb_entryId=6238445,cb_blogApp=currentBlogApp,cb_blogUserGuid='4f8b249b-def7-e411-b908-9dcfd8948a71',cb_entryCreatedDate='2016/12/30 22:25:00';loadViewCount(cb_entryId);
var commentManager = new blogCommentManager();commentManager.renderComments(0);
刷新评论刷新页面返回顶部
fixPostBody(); setTimeout(function () { incrementViewCount(cb_entryId); }, 50); deliverAdT2(); deliverAdC1(); deliverAdC2(); loadNewsAndKb(); loadBlogSignature(); LoadPostInfoBlock(cb_blogId, cb_entryId, cb_blogApp, cb_blogUserGuid); GetPrevNextPost(cb_entryId, cb_blogId, cb_entryCreatedDate); loadOptUnderPost(); GetHistoryToday(cb_blogId, cb_blogApp, cb_entryCreatedDate);

导航

博客园 首页 新随笔 联系 订阅 订阅 管理 loadBlogDefaultCalendar();

公告

loadBlogNews();
loadBlogSideColumn();

相关文章