也谈js函数节流
1、什么是js函数节流
其本质就是不让某些代码(函数)在没有间断的情况下连续重复执行,目的就是让执行函数的请求停止了一段时间后才执行。
2、函数节流运用的场景
窗口大小的改变(resize事件),滚动事件(scroll事件),鼠标移动事件(mousemove事件),touchmove事件(做过手机端的同学一定知道,手机中手指滑动其实触发了多次touchmove),我们在绑定这些事件的时候,函数会被多次执行,因为性能的需要,此时函数节流就派上用场!

3、函数节流的书写基本形式
网上也提供很多关于函数节流的模式,根据自身的需要,正常写法有以下几种:
(1)对象字面量的方式:
<script type="text/javascript">
var throttle={
timeoutId:null,
performProcessing:function(){
console.log("节流")
},
process:function(){
clearTimeout(this.timeoutId);
var that=this;//为什么要设置这个,亲,setTimeout可是会改变this的指针指向window哦
this.timeoutId=setTimeout(function(){that.performProcessing()},250)
}
}
window.onresize=function(){
throttle.process();
}
</script>
当调用process函数的时候,就清除timeoutId来阻止之前的队列函数,然后创建一个新的定时器去调用performProcessing。时间的间隔是250ms,指的是最后一次调用process()之后至少250ms后才会继续调用performProcessing。250ms,代表着在250ms的时间内,不管调用了多少次,performProcessing只会被执行一次(而且是在最后一次被调用的那个函数间隔250ms才添加到队列并执行,如果你一直不间断触发函数,那么performProcessing将永远不会被执行)。
(2)函数式的方式:
function throttle(method,context){
clearTimeout(method.tId);
method.tId=setTimeout(function(){
method.call(context) //改变作用域
},250)
}
function resizeFunc(){
console.log(1)
}
window.onresize=function(){
throttle(resizeFunc)
}
这种函数节流看来已经不错了,可是发现我们在调用的时候和第1种方式(对象字面量方式)是一样的,这个时候问题就来了。如果页面多次调用,显然这种方式是无法通过参数来改变函数执行的频率(delay),所以难形成共用!怎么办呢?

那是否有更好的方法呢?如果能把delay的参数放出来呢?所以有了下面的函数写法:
<script type="text/javascript">
var throttle = function(fn, delay){
var timer = null;
return function(){var context = this, args = arguments;
clearTimeout(timer);
timer = setTimeout(function(){
fn.apply(context, args);
}, delay);
};
};
function printed(){
console.log(1)
}
window.onresize=throttle(printed,250)
</script>
这种方式,脑海中想到的是闭包,没错!就是通过js的闭包的方式,返回函数,通过timer的变量来控制函数的执行!改造完成以后基本能够满足了我们的需求!感觉大功告成了,哈哈!

可是,发现了没有,如果我不间断地执行某个函数,假设执行了300ms后才停下来,那么意味着setTimeout只有在300ms后才添加到队列,然后执行,那我们所想象的mousemove不就是一闪一闪的结果吗?(因为执行的频率太多频繁而无法立即出发setTimeout),所以我们肯定有必要在规定的时间内,移动要执行某个函数一次,这样就可以必选视觉的误差!所以我们规定了某个函数在视觉允许的范围内,固定时间至少调用一次!
<script type="text/javascript">
function throttle(fn,delay,duration){
var timer=null,last_exec=0;
return function(){
var context=this,args=arguments,elapsed = +new Date();
clearTimeout(timer);
if(!last_exec){
last_exec = elapsed;
}
if(elapsed-last_exec > duration){
fn.apply(context, args);
last_exec=elapsed;
}else {
timer = setTimeout(function(){
fn.apply(context, args);
}, delay);
}
}
} function resizeFunc(){
console.log(1)
}
window.onresize=throttle(resizeFunc,50,5000)
</script>
函数的原理很简单,每次执行函数的时候,判断当前的时间elapsed与上一次函数执行的时间的间隔大于delay的时候(elapsed-last_exec)就执行函数fn,然后将last_exec设为当前的日期,这样就可以达到了我们的目的了!
到这里,认为节流的函数已经结束了饿,可是你看的越多发现自己越无知,有木有呢?因为jquery最近版本已经有了throttle的函数了,把其中的代码如下:
(function(window,undefined){
'$:nomunge';
var $ = window.jQuery || window.Cowboy || ( window.Cowboy = {} ),jq_throttle;
$.throttle = jq_throttle = function( delay, no_trailing, callback, debounce_mode ) {
var timeout_id,last_exec = 0;
if ( typeof no_trailing !== 'boolean' ) {
debounce_mode = callback;
callback = no_trailing;
no_trailing = undefined;
}
function wrapper() {
var that = this,
elapsed = +new Date() - last_exec,
args = arguments;
function exec() {
last_exec = +new Date();
callback.apply( that, args );
};
function clear() {
timeout_id = undefined;
};
if ( debounce_mode && !timeout_id ) {
exec();
}
timeout_id && clearTimeout( timeout_id );
if ( debounce_mode === undefined && elapsed > delay ) {
exec();
} else if ( no_trailing !== true ) {
timeout_id = setTimeout( debounce_mode ? clear : exec, debounce_mode === undefined ? delay - elapsed : delay );
}
};
if ( $.guid ) {
wrapper.guid = callback.guid = callback.guid || $.guid++;
}
return wrapper;
};
$.debounce = function( delay, at_begin, callback ) {
return callback === undefined
? jq_throttle( delay, at_begin, false )
: jq_throttle( delay, callback, at_begin !== false );
};
})(this);
throttle函数的几个参数的说明:
delay:延迟的时间(Number)
no_trailing:默认是false(Boolean),可选参数!如果是false,那么固定每个一段时间(delay)定会调用一次callBack函数,如果是true,那么意味着callBack只会执行最后一次在throttle函数被触发后(听起来晕晕的!请看下图):其实可以理解为:在250ms的时间内,如果函数200ms就执行完了,那么no_trailing=true的时候就不触发callBack,no_trailing=false的时候就促发callBack
// > Throttled with `no_trailing` specified as false or unspecified:
// > ||||||||||||||||||||||||| (pause) |||||||||||||||||||||||||
// > X X X X X X X X X X X X
// >
// > Throttled with `no_trailing` specified as true:
// > ||||||||||||||||||||||||| (pause) |||||||||||||||||||||||||
// > X X X X X X X X X X
callBack:就是间隔delay时间要执行的函数
debounce_mode:可选,不传递任何参数就是undefined!如果是传递的是false的时候,那么就是追后一次执行事件delay的时间后调用callBack(没有固定的时间调用一次),如果debounce_mode=true,事件触发后立刻执行callBack,最后一次事件在delay的时间后触发callBack,开始就触发callBack函数(debounce_mode=false则不是)
debounce函数的几个参数的说明:
delay:延迟的时间(Number)
at_begin:默认false,at_begin=false意味着callBack会在debounce函数最后一次触发函数后执行!
// > Debounced with `at_begin` specified as false or unspecified:
// > ||||||||||||||||||||||||| (pause) |||||||||||||||||||||||||
// > X X
// >
// > Debounced with `at_begin` specified as true:
// > ||||||||||||||||||||||||| (pause) |||||||||||||||||||||||||
// > X X
callBack:就是间隔delay时间要执行的函数。
到这里,函数节流就算结束了,jquery中的封装比较难理解!但是我们只要知道调用方式和参数的作用即可!最后附上参考的网址:
地址:http://benalman.com/projects/jquery-throttle-debounce-plugin/
也谈js函数节流的更多相关文章
- 浅谈JS函数节流及应用场景
说完防抖,下面我们讲讲节流,规矩就不说了,先上代码: <!DOCTYPE html> <html lang="en"> <head> <m ...
- 浅谈javascript函数节流
浅谈javascript函数节流 什么是函数节流? 函数节流简单的来说就是不想让该函数在很短的时间内连续被调用,比如我们最常见的是窗口缩放的时候,经常会执行一些其他的操作函数,比如发一个ajax请求等 ...
- js 函数节流和防抖
js 函数节流和防抖 throttle 节流 事件触发到结束后只执行一次. 应用场景 触发mousemove事件的时候, 如鼠标移动. 触发keyup事件的情况, 如搜索. 触发scroll事件的时候 ...
- Underscore.js 函数节流简单测试
函数节流在日常的DOM界面数据交互中有比较大的作用,可以减少服务器的请求,同时减少客户端的内存影响 Underscore.js 本省就包含了函数节流的处理函数 _.throttle 和 _.debo ...
- 结构-行为-样式-Js函数节流
最近一个面试官问了我一个函数节流的问题,然后感觉自己工作中遇到过这个问题,但是不知道这种形式就是函数节流.下面我来说下这个Js的高级问题,思路:函数节流就是防止用户高频调用某个事件而做的Js层面的处理 ...
- js 函数节流throttle 函数去抖debounce
1.函数节流throttle 通俗解释: 假设你正在乘电梯上楼,当电梯门关闭之前发现有人也要乘电梯,礼貌起见,你会按下开门开关,然后等他进电梯: 但是,你是个没耐心的人,你最多只会等待电梯停留一分钟: ...
- 深入理解JS函数节流和去抖动
一.什么是节流和去抖? 1.节流 节流就是拧紧水龙头让水少流一点,但是不是不让水流了.想象一下在现实生活中有时候我们需要接一桶水,接水的同时不想一直站在那等着,可能要离开一会去干一点别的事请,让水差不 ...
- JS函数节流和防抖
看JS高级程序设计时,了解到一个概念--函数节流,是为了防止在高频率触发某些事件导致浏览器崩溃.最近又了解到另一个概念,防抖,感觉和函数节流很像,也查看了很多篇博文,算是理解了. 区别: 函数节流:频 ...
- JS函数节流代码实现
函数被频繁调用场景 Js中的函数大多数情况下都是由用户主动调用触发的,一般不会遇到性能相关的问题.但在一些少数情况下,函数的触发不是由用户直接控制.在这些场景下,函数有可能被非常频繁地调用,而造成大的 ...
随机推荐
- struts2之chain的使用
/** * 实现功能表单提交给action1先处理,再交由action2进行处理,中间传递参数a,b **/ /** * 1. 配置文件 **/ <action name="actio ...
- iOS9基础知识(OC)笔记
1月16日 Objective C(20世纪80年代初) 一.OC语言概述 1.1985年,Steve Jobs成立了NeXT公司 2.1996年,12月20日,苹果公司宣布收购了NeXT ...
- NULL & nil & Nil & NSNULL的区别
nil 是 OC 的,空对象,地址指向 空(0) 的对象 在 OC 中,可以给空对象发送任何消息,不会出现错误 NULL 是 C 的,空地址,地址的数值是 0,是一个长整数 表示地址是空 NSNull ...
- SQL随机查询,显示行号,查询数据段
1.显示行号 如果数据没有删除的情况下主键与行号是一致的,但在删除某些数据,行号就与主键不一致了,这时需要查询行号就需要用新的方法,在SQL Server2005之前,需要使用临时表,但在SQL Se ...
- jquery 项目所用
<script> $(document).ready(function(){ $.ajax({ type:'post', url :'interface.ajax.php', data:{ ...
- [ofbiz]entitymode中类型的对照关系
在实体数据结构的时候,习惯于数据库的设计模式,int,varchar等各种类型,但是在entitymode中不是直接使用数据库的类型模式,而是自己定义了一套数据类型(type). 如何找到两者之间的对 ...
- Android反编译APK
http://blog.csdn.net/vipzjyno1/article/details/21039349/ 关于被加壳工具添加我的apk如何脱壳 http://www.blogfshare.co ...
- Eloquent ORM 之关联查询
小伙伴们好,本文是在我的前一篇随笔的基础上完成的,还没有浏览的同学,请移尊驾哦 Eloquent ORM学习笔记. 前一篇文章用到了leftJoin方法,其实Eloquent对于模块之间的关联查询有自 ...
- redis怎么动态添加内存,动态配置,无需重启。
在redis的使用过程中,有时候需要急需修改redis的配置,比如在业务运行的情况下,内存不够怎么办,这时要么赶紧删除无用的内存,要么扩展内存.如果有无用的内容可删除那么所有问题都已经解决.如果内容都 ...
- Linux系统下用C语言获取MAC地址
最近在做一个小程序,需要用到在linux系统里编写C程序从而获取MAC地址,从网上搜了一遍,想总结一下.如果你就只需要单个功能的程序,可以采用方法一,见代码1,一般最好能够封装起来,写成获取MAC地址 ...