JS中的函数节流throttle详解和优化
在前端开发中,有时会为页面绑定resize事件,或者为一个页面元素绑定拖拽事件(mousemove),这种事件有一个特点,在一个正常的操作中,有可能在一个短的时间内触发非常多次事件绑定程序。
DOM操作时很消耗性能的,如果你为这些事件绑定一些操作DOM节点的操作的话,那就会引发大量的计算,在用户看来,页面可能就一时间没有响应,这个页面一下子变卡了变慢了。在IE下,如果你绑定的resize事件进行较多DOM操作可能直接就崩溃了。

怎么解决?函数节流(throttle)就是一种办法。

函数节流的原理
某些代码不可以在没有间断的情况连续重复执行。
第一次调用函数,创建一个定时器,在指定的时间间隔之后运行代码。
当第二次调用该函数时,它会清除前一次的定时器并设置另一个。
如果前一个定时器已经执行过了,这个操作就没有任何意义。
然而,如果前一个定时器尚未执行,其实就是将其替换为一个新的定时器。
目的是只有在执行函数的请求停止了一段时间之后才执行。

简单点说就是:当触发一个事件时,先setTimout让这个事件延迟一会再执行,如果在这个时间间隔内又触发了事件,那我们就clear掉原来的定时器,再setTimeout一个新的定时器延迟一会执行。
实际使用过程中考虑到用户体验问题,会在这个基础上做一些优化。

一个简单实现的例子:
函数实现方式:

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

调用方法:

window.onresize = function(){
throttle(myFunc);
}

---------------

闭包实现方式:

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

调用方法:

window.onresize = throttle(myFunc, 50);
-------------
上面的函数节流有个问题是:只要你在50ms内不间断resize,myFunc就一次都不执行处理函数。
对上面的节流函数做拓展:

var throttleV2 = function(fn, delay, mustRunDelay){
var timer = null;
var t_start;
return function(){
var context = this, args = arguments, t_curr = +new Date();
clearTimeout(timer);
if(!t_start){
t_start = t_curr;
}
if(t_curr - t_start >= mustRunDelay){
fn.apply(context, args);
t_start = t_curr;
}
else {
timer = setTimeout(function(){
fn.apply(context, args);
}, delay);
}
};
};

拓展后的节流函数升级版,可以设置第三个参数,即必须触发执行的时间间隔。

方法调用:
window.onresize = throttleV2(myFunc, 50, 100);

50ms的间隔内连续触发的调用,后一个调用会把前一个调用的等待处理掉,但每隔100ms至少执行一次。
一开始记录第一次调用的时间戳,然后每次调用函数都去拿最新的时间跟记录时间比,超出给定的时间就执行一次,更新记录时间。

-----------------
例子场景2:实现常见的搜索功能
1.没有使用函数节流的情况下,为input绑定keyup事件处理函数,在控制台输出我输入的内容。
每按下一个键盘键,就输出了一次。短短的一些内容,输出了15次,如果每一次都是一次ajax查询请求的话就发了14个请求了。在性能上的消耗可想而知。
假如我不断地输入,输入了很多内容,但是我每两次之间的输入间隔都小于自己设置的delay值,那么,这个queryData搜索函数就一直得不到调用。实际上,我们更希望的是,当达到某个时间值时,一定要执行一次这个搜索函数。所以,就有了函数节流的改进模式。

函数节流增强版
HTML:
<input id="search" type="text" name="search">
JS:

    <script>
function queryData(text){
console.log("搜索:" + text);
}
var input = document.getElementById("search");
input.addEventListener("keyup", function(event){
throttle(queryData, null, 500, this.value,1000);
// throttle(queryData, null, 500, this.value);
// queryData(this.value);
}); function throttle(fn,context,delay,text,mustApplyTime){
clearTimeout(fn.timer);
fn._cur=Date.now(); //记录当前时间 if(!fn._start){ //若该函数是第一次调用,则直接设置_start,即开始时间,为_cur,即此刻的时间
fn._start=fn._cur;
}
if(fn._cur-fn._start>mustApplyTime){
//当前时间与上一次函数被执行的时间作差,与mustApplyTime比较,若大于,则必须执行一次函数,若小于,则重新设置计时器
fn.call(context,text);
fn._start=fn._cur;
}else{
fn.timer=setTimeout(function(){
fn.call(context,text);
},delay);
}
}
</script>

显然,连续的输入,到一定时间间隔之后,queryData函数必然会被调用,但是又不是频繁的调用。达到了节流的目的,又不会影响用户体验。

进一步的优化可以在调用throttle函数之前,先对输入的内容进行判断,若其值为空、值不变不调用。

JS中的函数节流throttle详解和优化的更多相关文章

  1. Node.js中环境变量process.env详解

    Node.js中环境变量process.env详解process | Node.js API 文档http://nodejs.cn/api/process.html官方解释:process 对象是一个 ...

  2. 谈谈JS中的函数节流

    好吧,一直在秋招中,都没怎么写博客了...今天赶紧来补一补才行...我发现,在面试中,讲到函数节流好像可以加分,尽管这并不是特别高深的技术,下面就聊聊吧! ^_^ 备注:以下内容部分来自<Jav ...

  3. [转] 谈谈JS中的函数节流

    函数节流的目的 从字面上就可以理解,函数节流就是用来节流函数从而一定程度上优化性能的.例如,DOM 操作比起非DOM 交互需要更多的内存和CPU 时间.连续尝试进行过多的DOM 相关操作可能会导致浏览 ...

  4. 【javascript】js中的函数节流和函数防抖

    一.概念解释  函数节流和函数防抖,两者都是优化高频率执行js代码的一种手段.  大家大概都知道旧款电视机的工作原理,就是一行行得扫描出色彩到屏幕上,然后组成一张张图片.由于肉眼只能分辨出一定频率的变 ...

  5. JS中的函数节流

    函数节流的目的 从字面上就可以理解,函数节流就是用来节流函数从而一定程度上优化性能的.例如,DOM 操作比起非DOM 交互需要更多的内存和CPU时间.连续尝试进行过多的DOM 相关操作可能会导致浏览器 ...

  6. js中的preventDefault与stopPropagation详解

    本篇文章主要是对js中的preventDefault与stopPropagation进行了介绍,需要的朋友可以过来参考下,希望对大家有所帮助 首先讲解一下js中preventDefault和stopP ...

  7. MySQL中count函数使用方法详解

      count函数是用来统计表中或数组中记录的一个函数,下面我来介绍在MySQL中count函数用法与性能比较吧. count(*) 它返回检索行的数目, 不论其是否包含 NULL值. SELECT ...

  8. PHP中spl_autoload_register()函数用法实例详解

    本文实例分析了PHP中spl_autoload_register()函数用法.分享给大家供大家参考,具体如下: 在了解这个函数之前先来看另一个函数:__autoload. 一.__autoload 这 ...

  9. 现代JS中的流程控制:详解Callbacks 、Promises 、Async/Await

    JavaScript经常声称是_异步_.那是什么意思?它如何影响发展?近年来这种方法有何变化? 请思考以下代码: result1 = doSomething1(); result2 = doSomet ...

随机推荐

  1. react native获取屏幕的宽度和高度

    var Dimensions = require('Dimensions'); var {width,height} = Dimensions.get("window");//第一 ...

  2. 可快速生成增删curd改查功能的插件

    仿造Django中的admin自己实现增删改查.模糊搜索.批量操作.条件筛选.popup功能的插件 1.创建组件 首先创建一个app,这里取名为stark,在settings.py中将其进行注册 IN ...

  3. Windows XP解决显示桌面图标消失的问题

    1.依次单击“开始”,“运行”,在运行对话框中输入regsvr32 /n /i:u shell32.dll,按回车键 2.弹出“shell32.dll中的DllInstall成功”的窗口,表明已将数据 ...

  4. Font Awesome 最简单应用例子

    简介: Font Awesome为您提供可缩放的矢量图标,您可以使用CSS所提供的所有特性对它们进行更改,包括:大小.颜色.阴影或者其它任何支持的效果. 使用方法: 引入<link rel=&q ...

  5. PHP MYSQL 临时表的使用

    /** * 临时表:用于获取爱鸽登录分类数量 */ $temporaryTableName = uniqid('temporary_'); $model = M(); $model->execu ...

  6. [py]字符串转换为列表

    字符串转换为列表 "[1,2,3]" ==> [1,2,3]

  7. throws和throw的区别

    throws是声明在方法上,告诉调用者这个方法可能会出现的问题.格式  :   方法()   throws  自定义异常类(异常类)    就是在这个方法里面会出问题时,new  throw时,    ...

  8. PHP中parent、this、self和static的区别

    参考: http://www.cnblogs.com/devcjq/articles/2424738.html http://www.cnblogs.com/alsf/p/9621002.html h ...

  9. nodejs 网上下载图片到本地,并判断图片路径是否存在

    var http = require("http"); var fs = require("fs"); var server = http.createServ ...

  10. 使用 nghttpx 搭建 HTTP/2 代理 (转)

    来自http://www.fanyue.info/2015/08/nghttpx-http2.html 使用 nghttpx 搭建 HTTP/2 代理 [转] HTTP/1.1,定义于 1999 年, ...