JavaScript函数节流概念与用法实例详解


Posted in Javascript onJune 20, 2016

本文实例讲述了JavaScript函数节流概念与用法。分享给大家供大家参考,具体如下:

最近在做网页的时候有个需求,就是浏览器窗口改变的时候需要改一些页面元素大小,于是乎很自然的想到了window的resize事件,于是乎我是这么写的

<!DOCTYPE html>
<html>
<head>
  <title>Throttle</title>
</head>
<body>
  <script type="text/javascript">
    n=0;
    function resizehandler(){
      console.log(new Date().getTime());
      console.log(++n);
    }
    window.onresize=resizehandler;
  </script>
</body>
</html>

功能倒是实现了,但是我拖拽的方式改变浏览器窗口大小的时候看了下控制台

JavaScript函数节流概念与用法实例详解

没错,简单的一个拖拽让我的resizeHandler()方法执行了52次,这完全不是我想要的效果,实际上我的resizeHandler()方法的代码很复杂,甚至会使用ajax向服务器发送请求,要是简单的一次改变窗口大小就要调用52次这还了得

函数节流

其实我的本意只是窗口resize后页面做一些调整就可以,而window的resize事件并不是在resize结束后才触发的,具体则么个频率我也不知道,但却是在不停的调用,直到窗口大小不再变化。其实类似的机制还有鼠标的mousemove,都是在短时间内重复触发。

在《JavaScript高级程序设计》中有专门应对此问题的函数节流

function throttle(method,context){
  clearTimeout(method.tId);
  method.tId=setTimeout(function(){
    method.call(context);
  },500);
}

原理很简单,利用定时器,让函数执行延迟500毫秒,在500毫秒内如果有函数又被调用则删除上一次调用,这次调用500毫秒后执行,如此往复。这样我刚才的代码可以改为

<script type="text/javascript">
n=0;
function resizehandler(){
  console.log(new Date().getTime());
  console.log(++n);
}
function throttle(method,context){
  clearTimeout(method.tId);
  method.tId=setTimeout(function(){
    method.call(context);
  },500);
}
window.onresize=function(){
  throttle(resizehandler,window);
};
</script>

拖拽一下试试,果真只执行了一次

JavaScript函数节流概念与用法实例详解

另一种做法

网上还有一种函数节流方案,它是这么做的

function throttle(method,delay){
  var timer=null;
  return function(){
    var context=this, args=arguments;
    clearTimeout(timer);
    timer=setTimeout(function(){
      method.apply(context,args);
    },delay);
  }
}

调用一下试试,一样的效果

<script type="text/javascript">
n=0;
function resizehandler(){
  console.log(new Date().getTime());
  console.log(++n);
}
function throttle(method,delay){
  var timer=null;
  return function(){
    var context=this, args=arguments;
    clearTimeout(timer);
    timer=setTimeout(function(){
      method.apply(context,args);
    },delay);
  }
}
window.onresize=throttle(resizehandler,500);//因为返回函数句柄,不用包装函数了
</script>

JavaScript函数节流概念与用法实例详解

比较

两种方法都是利用了setTimeout,不同的是第二种方法加入的函数延迟执行时间,这个在第一种方案中很容易也具有此功能,加一个参数的事儿。

但第一种方案把tId设为函数的一个变量保存,而第二种创建了一个闭包来存储。个人觉得差距不大,很喜欢第一种,简单,高效。

新需求

有一天做了个类似的东西,就像百度首页输入自动提示一样的东西,我在text上绑定keyup事件,每次键盘弹起的时候自动提示,但是又不想提示那么频繁,于是我用了上面方法,但是悲剧了,只有停止输入等500毫秒才会提示,在输入过程中根本就没有提示。看了一下代码,可不是嘛,只要是用户会盲打,在500毫秒内按一下键盘,提示函数就会不断被延迟,这样只有停下来的时候才会提示,这就没意义了。

能不能在函数节流的基础上间隔固定时间就执行一次?

小改动

在网上搜了一下我们可以根据第二种写法(第一种为函数拓展多个变量感觉有些不好)做些改动,添加一个参数作为到固定间隔必须执行

function throttle(method,delay,duration){
  var timer=null, begin=new Date();
  return function(){
    var context=this, args=arguments, current=new Date();;
    clearTimeout(timer);
    if(current-begin>=duration){
       method.apply(context,args);
       begin=current;
    }else{
      timer=setTimeout(function(){
        method.apply(context,args);
      },delay);
    }
  }
}

这样每次我们判断间隔了多久,要是超过设置时间则立即执行一次,以刚才例子试一试效果

window.onresize=throttle(resizehandler,100,200);

JavaScript函数节流概念与用法实例详解

果真既没有频繁执行也没有就最后执行

希望本文所述对大家JavaScript程序设计有所帮助。

Javascript 相关文章推荐
jQuery 判断元素上是否绑定了事件
Oct 28 Javascript
JS实现多物体缓冲运动实例代码
Nov 29 Javascript
常见浏览器多长时间会提示“脚本运行时间过长”总结
Apr 29 Javascript
jQuery事件绑定和委托实例
Nov 25 Javascript
JavaScript中rem布局在react中的应用
Dec 09 Javascript
javascript模块化简单解析
Apr 07 Javascript
Angularjs之filter过滤器(推荐)
Nov 27 Javascript
手把手教你写一个微信小程序(推荐)
Oct 17 Javascript
生成无限制的微信小程序码的示例代码
Sep 20 Javascript
layui实现图片虚拟路径上传,预览和删除的例子
Sep 25 Javascript
Ant design vue table 单击行选中 勾选checkbox教程
Oct 24 Javascript
vue cli4中mockjs在dev环境和build环境的配置详情
Apr 06 Vue.js
Angular的Bootstrap(引导)和Compiler(编译)机制
Jun 20 #Javascript
jquery通过name属性取值的简单实现方法
Jun 20 #Javascript
jQuery模拟select实现下拉菜单功能
Jun 20 #Javascript
对jQuary选择器的全面总结
Jun 20 #Javascript
jQuery实现的可编辑表格完整实例
Jun 20 #Javascript
jQuery文件上传控件 Uploadify 详解
Jun 20 #Javascript
javascript js 操作数组 增删改查的简单实现
Jun 20 #Javascript
You might like
dedecms系统常用术语汇总
2007/04/03 PHP
PHP代码优化的53个细节
2014/03/03 PHP
PHP 微信扫码支付源代码(推荐)
2016/11/03 PHP
ajax更新数据后,jquery、jq失效问题
2011/03/16 Javascript
调用innerHTML之后onclick失效问题的解决方法
2014/01/28 Javascript
js获得参数的getParameter使用示例
2014/02/26 Javascript
javascript实现锁定网页、密码解锁效果(类似系统屏幕保护效果)
2014/08/15 Javascript
原生javascript实现获取指定元素下所有后代元素的方法
2014/10/28 Javascript
jquery制作 随机弹跳的小球特效
2015/02/01 Javascript
详解JavaScript中循环控制语句的用法
2015/06/03 Javascript
JS实现超精简的链接列表在固定区域内滚动效果代码
2015/11/04 Javascript
详解webpack 入门总结和实践(按需异步加载,css单独打包,生成多个入口文件)
2017/06/20 Javascript
解决vue多个路由共用一个页面的问题
2018/03/12 Javascript
AngularJS $http post 传递参数数据的方法
2018/10/09 Javascript
vue实现移动端拖动排序
2020/08/21 Javascript
[01:00]DOTA2 store: Collection of Artisan's Wonders
2015/08/12 DOTA
[49:41]NB vs NAVI Supermajor小组赛A组 BO3 第一场 6.2
2018/06/03 DOTA
[56:14]Fnatic vs OG 2018国际邀请赛小组赛BO2 第二场 8.18
2018/08/19 DOTA
pandas DataFrame数据转为list的方法
2018/04/11 Python
浅谈Django中的数据库模型类-models.py(一对一的关系)
2018/05/30 Python
使用TensorFlow实现SVM
2018/09/06 Python
python数据归一化及三种方法详解
2019/08/06 Python
python动态文本进度条的实例代码
2020/01/22 Python
keras slice layer 层实现方式
2020/06/11 Python
吃透移动端 1px的具体用法
2019/12/16 HTML / CSS
Missguided美国官网:英国时尚品牌
2018/01/18 全球购物
美国在线奢侈品寄售商店:Luxury Garage Sale
2018/08/19 全球购物
网络安全类面试题
2015/08/01 面试题
幼儿园家长寄语
2014/04/02 职场文书
出国留学担保书
2014/05/20 职场文书
金融专业毕业生自荐信
2014/06/26 职场文书
2015毕业生自我评价范文
2015/03/02 职场文书
2015年小学体育教师工作总结
2015/10/23 职场文书
《鸟的天堂》教学反思
2016/02/19 职场文书
golang 实现菜单树的生成方式
2021/04/28 Golang
MySQL kill不掉线程的原因
2021/05/07 MySQL