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 相关文章推荐
event.currentTarget与event.target的区别介绍
Dec 31 Javascript
js substring从右边获取指定长度字符串(示例代码)
Dec 23 Javascript
javascript/jquery获取地址栏url参数的方法
Mar 05 Javascript
jQuery+jsp实现省市县三级联动效果(附源码)
Dec 03 Javascript
js实现可控制左右方向的无缝滚动效果
May 29 Javascript
JavaScript中in和hasOwnProperty区别详解
Aug 04 Javascript
Vue组件中的data必须是一个function的原因浅析
Sep 03 Javascript
Vue+webpack项目配置便于维护的目录结构教程详解
Oct 14 Javascript
教你如何编写Vue.js的单元测试的方法
Oct 17 Javascript
通过javascript实现段落的收缩与展开
Jun 26 Javascript
详解vue-cli项目开发/生产环境代理实现跨域请求
Jul 23 Javascript
解决vue v-for src 图片路径问题 404
Nov 12 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
Cappuccino 卡布其诺咖啡之制作
2021/03/03 冲泡冲煮
PHP 程序员也要学会使用“异常”
2009/06/16 PHP
PHP 上传文件大小限制
2009/07/05 PHP
解析PHP无限级分类方法及代码
2013/06/21 PHP
PHP实现的MongoDB数据库操作类分享
2014/05/12 PHP
测试JavaScript字符串处理性能的代码
2009/12/07 Javascript
jquery获得页面元素的坐标值实现思路及代码
2013/04/15 Javascript
浏览器打开层自动缓慢展开收缩实例代码
2013/07/04 Javascript
对Jquery中的ajax再封装,简化操作示例
2014/02/12 Javascript
基于BootStrap Metronic开发框架经验小结【六】对话框及提示框的处理和优化
2016/05/12 Javascript
Bootstrap Table的使用总结
2016/10/08 Javascript
微信开发 JS-SDK 6.0.2 经常遇到问题总结
2016/12/08 Javascript
Vue.js学习之计算属性
2017/01/22 Javascript
基于JavaScript实现类名的添加与移除
2017/04/23 Javascript
微信小程序--组件(swiper)详细介绍
2017/06/13 Javascript
浅谈React中的元素、组件、实例和节点
2018/02/27 Javascript
vue-cli 默认路由再子路由选中下的选中状态问题及解决代码
2018/09/06 Javascript
[00:12]DAC SOLO赛卫冕冠军 VG.Paparazi灬展现SOLO技巧
2018/04/06 DOTA
[05:08]DOTA2-DPC中国联赛3月6日Recap集锦
2021/03/11 DOTA
python爬虫实战之爬取京东商城实例教程
2017/04/24 Python
Python使用matplotlib绘图无法显示中文问题的解决方法
2018/03/14 Python
python使用socket创建tcp服务器和客户端
2018/04/12 Python
python 通过类中一个方法获取另一个方法变量的实例
2019/01/22 Python
Python实现的登录验证系统完整案例【基于搭建的MVC框架】
2019/04/12 Python
Python异常处理例题整理
2019/07/07 Python
解决pyPdf和pyPdf2在合并pdf时出现异常的问题
2020/04/03 Python
英国领先的品牌珠宝和配件供应商:Acotis Jewellery
2018/03/07 全球购物
荷兰照明、灯具和配件网上商店:dmlights
2019/08/25 全球购物
Chain Reaction Cycles俄罗斯:世界上最大的在线自行车商店
2019/08/27 全球购物
丝芙兰墨西哥官网:Sephora墨西哥
2020/05/30 全球购物
用Python匹配HTML tag的时候,<.*>和<.*?>有什么区别
2012/11/04 面试题
毕业生动漫设计求职信
2013/10/11 职场文书
简历中个人自我评价范文
2013/12/26 职场文书
农村结婚典礼主持词
2015/06/29 职场文书
小学二年级语文教学反思
2016/03/03 职场文书
dubbo服务整合zipkin详解
2021/07/26 Java/Android