JavaScript 函数节流详解及方法总结


Posted in Javascript onFebruary 09, 2017

JavaScript 函数节流详解

浏览器一个网页的UI线程只有一个,他同时会处理界面的渲染和页面JavaScript代码的执行(简单扩展一下,浏览器或者JavaScript运行大环境并不是单线程,诸如ajax异步回调、hybrid框架内与native通信、事件队列、CSS运行线程等等都属于多线程环境,不过ES6引入了Promise类来减少了部分异步情况)。因此当JavaScript代码运行计算量很大的方法时,就有可能阻塞UI线程,小则导致用户响应卡顿,严重的情况下浏览器会提示页面无响应是否强制关闭。例如网页的页面滚动事件、移动设备的滑动、缩放事件等。即使没有出现严重的性能问题,我们也应该站在性能优化的角度将短时间内会多次触发的大规模处理时间进行分流计算。

如何有效避免UI线程运行过长的代码,是所有用户交互应用需要考虑的问题,同样的问题在客户端Android可以使用UI主线程开子线程来分散计算。与此对应的,js也可以通过引入webWorker来分散计算,但是在js中有一个更简单并且效果不错的方法:函数节流。使用函数节流的核心技巧就是使用定时器分段计算。具体的实现方式大致有两种思路。

·方法一

1.这种实现方式的思路很好理解:设置一个一间隔时间,比如50毫秒,以此时间为基准设置定时器,当第一次触发事件到第二次触发事件间隔小于50毫秒时,清除这个定时器,并设置一个新的定时器,以此类推,直到有一次事件触发后50毫秒内没有重复触发。代码如下:

function debounce(method){ 
  clearTimeout(method.timer); 
  method.timer=setTimeout(function(){ 
   method(); 
  },50); 
}

这种设计方式有一个问题:本来应该多次触发的事件,可能最终只会发生一次。具体来说,一个循序渐进的滚动事件,如果用户滚动太快速,或者程序设置的函数节流间隔时间太长,那么最终滚动事件会呈现为一个很突然的跳跃事件,中间过程都被节流截掉了。这个例子举的有点夸张了,不过使用这种方式进行节流最终是会明显感受到程序比不节流的时候“更突兀”,这对于用户体验是很差的。有一种弥补这种缺陷的设计思路。

·方法二

2.第二种实现方式的思路与第一种稍有差别:设置一个间隔时间,比如50毫秒,以此时间为基准稳定分隔事件触发情况,也就是说100毫秒内连续触发多次事件,也只会按照50毫秒一次稳定分隔执行。代码如下:

var oldTime=new Date().getTime(); 
var delay=50; 
function throttle1(method){ 
  var curTime=new Date().getTime(); 
  if(curTime-oldTime>=delay){ 
   oldTime=curTime; 
   method(); 
  } 
}

相比于第一种方法,第二种方法也许会比第一种方法执行更多次(有时候意味着更多次请求后台,即更多的流量),但是却很好的解决了第一种方法清除中间过程的缺陷。因此在具体场景应根据情况择优决定使用哪种方法。

对于方法二,我们再提供另一种同样功能的写法:

var timer=undefined,delay=50; 
function throttle2(method){ 
  if(timer){ 
    return ; 
  } 
  method(); 
  timer=setTimeout(function(){ 
    timer=undefined; 
  },delay); 
}

最后说点个外话,说明一下函数节流的名称问题,大家往往会看到throttle和debounce两个方法名,throttle可以译为“节制,卡住”,debounce可以译为“防反跳”。在《JavaScript高级程序设计》中作者介绍了方法一,并且作者使用了“throttle”这个函数名。而在《第三方JavaScript编程》书中同时出现了方法一和方法二,作者将方法一命名为“debounce”,将方法二命名为“throttle”。国内在同时介绍两个方法的时候有些文章错误的将方法一命名为“throttle”,而将方法二命名为“debounce”,从英语的角度来说是很不负责任的。因此在这里拨乱反正:方法一适合理解为“防反跳”,应命名为“debounce”;方法二适合理解为“函数节制”,应命名为“throttle”。

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

Javascript 相关文章推荐
js报错 Object doesn't support this property or method的原因分析
Mar 31 Javascript
chrome原生方法之数组
Nov 30 Javascript
jquery $.getJSON()跨域请求
Dec 21 Javascript
javascript 另一种图片滚动切换效果思路
Apr 20 Javascript
禁止iframe页面的所有js脚本如alert及弹出窗口等
Sep 03 Javascript
JavaScript闭包详解
Feb 02 Javascript
js+flash实现的5图变换效果广告代码(附演示与demo源码下载)
Apr 01 Javascript
js和C# 时间日期格式转换的简单实例
May 28 Javascript
jQuery轮播图效果精简版完整示例
Sep 04 Javascript
Vue2.0 slot分发内容与props验证的方法
Dec 12 Javascript
Vue的props父传子的示例代码
May 20 Javascript
小程序实现侧滑删除功能
Jun 25 Javascript
jQuery实现给input绑定回车事件的方法
Feb 09 #Javascript
jQuery分页插件jquery.pagination.js使用方法解析
Feb 09 #Javascript
Bootstrap面板学习使用
Feb 09 #Javascript
详解js的异步编程技术的方法
Feb 09 #Javascript
原生JS实现简单放大镜效果
Feb 08 #Javascript
基于JavaScript实现本地图片预览
Feb 08 #Javascript
js 判断登录界面的账号密码是否为空
Feb 08 #Javascript
You might like
开发大型 PHP 项目的方法
2007/01/02 PHP
php中用文本文件做数据库的实现方法
2008/03/27 PHP
一篇有意思的技术文章php介绍篇
2010/10/26 PHP
Using the TextRange Object
2006/10/14 Javascript
JS中令人发指的valueOf方法介绍
2013/02/22 Javascript
js判断文本框剩余可输入字数的方法
2015/02/04 Javascript
javascript变量声明实例分析
2015/04/25 Javascript
jQuery实现带滑动条的菜单效果代码
2015/08/26 Javascript
javascript动态添加checkbox复选框的方法
2015/12/23 Javascript
jQuery实现的网页换肤效果示例
2016/09/20 Javascript
js实现table添加行tr、删除行tr、清空行tr的简单实例
2016/10/15 Javascript
Vue-Router实现页面正在加载特效方法示例
2017/02/12 Javascript
如何用js判断dom是否有存在某class的值
2017/02/13 Javascript
JavaScript设计模式之工厂模式简单实例教程
2018/07/03 Javascript
vue.js实现的绑定class操作示例
2018/07/06 Javascript
vue动画之点击按钮往上渐渐显示出来的实例
2018/09/29 Javascript
详解js动态获取浏览器或页面等容器的宽高
2019/03/13 Javascript
[52:52]完美世界DOTA2联赛PWL S3 LBZS vs access 第一场 12.10
2020/12/13 DOTA
Python实现的检测网站挂马程序
2014/11/30 Python
Python实现获取命令行输出结果的方法
2017/06/10 Python
基于numpy.random.randn()与rand()的区别详解
2018/04/17 Python
django项目中使用手机号登录的实例代码
2019/08/15 Python
python3 sorted 如何实现自定义排序标准
2020/03/12 Python
基于Python pyecharts实现多种图例代码解析
2020/08/10 Python
Django Auth用户认证组件实现代码
2020/10/13 Python
CSS3的 fit-content实现水平居中
2017/09/07 HTML / CSS
HTML5的标签的代码的简单介绍 HTML5标签的简介
2012/05/28 HTML / CSS
学雷锋树新风演讲稿
2014/05/10 职场文书
选秀节目策划方案
2014/06/06 职场文书
我的中国梦口号
2014/06/16 职场文书
小学教师学习党的群众路线教育实践活动心得体会
2014/10/31 职场文书
2015年学校总务处工作总结
2015/05/19 职场文书
本科毕业论文答辩稿
2015/06/23 职场文书
解决ObjectMapper.convertValue() 遇到的一些问题
2021/06/30 Java/Android
Redis字典实现、Hash键冲突及渐进式rehash详解
2021/09/04 Redis
Window server中安装Redis的超详细教程
2021/11/17 Redis