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 关键字“拖曳搜索”之“拖曳”以及 图片“提示自适应放大”效果 的实现
Apr 18 Javascript
Javascript OOP之面向对象
Jul 31 Javascript
浅谈toLowerCase和toLocaleLowerCase的区别
Aug 15 Javascript
关于jquery中动态增加select,事件无效的快速解决方法
Aug 29 Javascript
微信小程序开发一键登录 获取session_key和openid实例
Nov 23 Javascript
JavaScript正则表达式小结(test|match|search|replace|split|exec)
Dec 08 Javascript
JS闭包的几种常见形式实例详解
Sep 16 Javascript
用 Vue.js 递归组件实现可折叠的树形菜单(demo)
Dec 25 Javascript
ES6之模版字符串的具体使用
May 17 Javascript
详解Vue底部导航栏组件
May 02 Javascript
JavaScript常用工具函数汇总(浏览器环境)
Sep 17 Javascript
vue 解决IOS10低版本白屏的问题
Nov 17 Javascript
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
调频问题解答
2021/03/01 无线电
PHP学习之整理字符串
2011/04/17 PHP
PHP 安全检测代码片段(分享)
2013/07/05 PHP
php使用filter过滤器验证邮箱 ipv6地址 url验证
2013/12/25 PHP
Nginx下配置codeigniter框架方法
2015/04/07 PHP
php curl请求信息和返回信息设置代码实例
2015/04/27 PHP
初学js 新节点的创建 删除 的步骤
2011/07/04 Javascript
IE下使用jQuery重置iframe地址时内存泄露问题解决办法
2015/02/05 Javascript
移动Web中图片自适应的两种JavaScript解决方法
2015/06/18 Javascript
javascript实现网页字符定位的方法
2015/07/14 Javascript
jQuery使用$.each遍历json数组的简单实现方法
2016/04/18 Javascript
jquery轮播的实现方式 附完整实例
2016/07/28 Javascript
Javascript函数中的arguments.callee用法实例分析
2016/09/16 Javascript
Angular 4依赖注入学习教程之ClassProvider的使用(三)
2017/06/04 Javascript
vue.js中v-on:textInput无法执行事件问题的解决过程
2017/07/12 Javascript
jQueryMobile之窗体长内容的缺陷与解决方法实例分析
2017/09/20 jQuery
详解使用React进行组件库开发
2018/02/06 Javascript
使用flow来规范javascript的变量类型
2019/09/12 Javascript
JS实现简单打字测试
2020/06/24 Javascript
vue 实现根据data中的属性值来设置不同的样式
2020/08/04 Javascript
跟老齐学Python之坑爹的字符编码
2014/09/28 Python
详解Python中的循环语句的用法
2015/04/09 Python
Python yield 使用浅析
2015/05/28 Python
Python 专题五 列表基础知识(二维list排序、获取下标和处理txt文本实例)
2017/03/20 Python
python实现flappy bird游戏
2018/12/24 Python
python开发之anaconda以及win7下安装gensim的方法
2019/07/05 Python
python 用opencv实现霍夫线变换
2020/11/27 Python
Rodd & Gunn澳大利亚官网:新西兰男装品牌
2018/09/25 全球购物
Unix控制后台进程都有哪些进程
2016/09/22 面试题
消防安全检查制度
2014/02/04 职场文书
员工拓展培训方案
2014/02/15 职场文书
建设工地安全标语
2014/06/07 职场文书
工作所在部门证明
2014/09/21 职场文书
在pyCharm中下载第三方库的方法
2021/04/18 Python
Django利用AJAX技术实现博文实时搜索
2021/05/06 Python
HTML 里 img 元素的 src 和 srcset 属性的区别详解
2023/05/21 HTML / CSS