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 相关文章推荐
获取当前网页document.url location.href区别总结
May 10 Javascript
JS 遮照层实现代码
Mar 31 Javascript
jQuery使用一个按钮控制图片的伸缩实现思路
Apr 19 Javascript
js中文逗号转英文实现
Feb 11 Javascript
浅谈javascript实现八大排序
Apr 27 Javascript
基于touch.js手势库+zepto.js插件开发图片查看器(滑动、缩放、双击缩放)
Nov 17 Javascript
js实现百度地图定位于地址逆解析,显示自己当前的地理位置
Dec 08 Javascript
原生JS实现图片轮播效果
Dec 26 Javascript
js实现移动端导航点击自动滑动效果
Jul 18 Javascript
vue中实现左右联动的效果
Jun 22 Javascript
Vue项目结合Vue-layer实现弹框式编辑功能(实例代码)
Mar 11 Javascript
vue+animation实现翻页动画
Jun 29 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 以POST方式提交XML、获取XML,解析XML详解及实例
2016/10/26 PHP
PHP实现的迪科斯彻(Dijkstra)最短路径算法实例
2017/09/16 PHP
PHP实现字符串的全排列详解
2019/04/24 PHP
Javascript闭包用法实例分析
2015/01/23 Javascript
javascript实现通过表格绘制颜色填充矩形的方法
2015/04/21 Javascript
javascript中checkbox使用方法实例演示
2015/11/19 Javascript
Bootstrap每天必学之按钮
2015/11/26 Javascript
JQuery DIV 动态隐藏和显示的方法
2016/06/23 Javascript
js生成随机数方法和实例
2017/01/17 Javascript
javascript表单正则应用
2017/02/04 Javascript
JS中使用 after 伪类清除浮动实例
2017/03/01 Javascript
JS自定义函数实现时间戳转换成date的方法示例
2017/08/27 Javascript
JS控制GIF图片的停止与显示
2019/10/24 Javascript
ElementUI中el-tree节点的操作的实现
2020/02/27 Javascript
如何在微信小程序中使用骨架屏的步骤
2020/06/12 Javascript
原生JS运动实现轮播图
2021/01/02 Javascript
python解决字典中的值是列表问题的方法
2013/03/04 Python
python实现连接mongodb的方法
2015/05/08 Python
Python表示矩阵的方法分析
2017/05/26 Python
Django 登陆验证码和中间件的实现
2018/08/17 Python
numpy 返回函数的上三角矩阵实例
2019/11/25 Python
python基于TCP实现的文件下载器功能案例
2019/12/10 Python
python GUI库图形界面开发之PyQt5控件QTableWidget详细使用方法与属性
2020/02/25 Python
python实现吃苹果小游戏
2020/03/21 Python
国际知名设计师时装商店:Coggles
2016/09/05 全球购物
加拿大女装网上购物:Reitmans
2016/10/20 全球购物
DogBuddy荷兰:找到你最完美的狗保姆
2019/04/17 全球购物
SQL注入攻击的种类有哪些
2013/12/30 面试题
婚前协议书范本
2014/04/15 职场文书
交通事故委托书范本
2014/09/28 职场文书
骨干教师申报材料
2014/12/17 职场文书
试用期辞职信范文
2015/03/02 职场文书
2015年端午节国旗下演讲稿
2015/03/19 职场文书
python3.7.2 tkinter entry框限定输入数字的操作
2021/05/22 Python
SpringBoot集成Redis的思路详解
2021/10/16 Redis
SQL中的连接查询详解
2022/06/21 SQL Server