JavaScript中函数节流的理解
函数节流的原理
函数节流,就是对会频繁触发的函数事件做一些限制,让这些函数可以在每隔一定的时间或者每次满足一定的条件下再触发。一般我们会给他起一个名字throttle。也就是节流的意思。一般这样的函数有 resize事件、ontouchmove事件等。
举个简单的例子
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>测试函数节流</title>
<style>
#container{
width: 100%;
height: 200px;
border: 1px solid #646464;
color: #000000;
}
</style>
</head>
<body >
<div id="container"></div>
</body>
<script>
function alertSomething(){
alert("您的鼠标正在移动");
};
document.getElementById("container").onmousemove = alertSomething;
</script>
</html>
上面的代码就是简单的渲染出来一个div 然后给这个div绑定了一个鼠标移动事件。但是我们在实际情况下,这种体验是不好的,因为这个事件会被十分频繁的触发。只要我们在这个div上移动鼠标就会弹出这个阻塞性的事件alert,所以我们希望每隔一定时间提醒一下“您的鼠标正在移动”。
下面写一个节流的函数throttle()。
function throttle(func){
var timer;
return function(){
var context = this;
var args = arguments;
clearTimeout(timer);
timer = setTimeout(function(){
func.apply(context,args);
},1000);
}
}
然后我们修改一下页面上的代码:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>测试函数节流</title>
<style>
#container{
width: 100%;
height: 200px;
border: 1px solid #646464;
color: #000000;
}
</style>
</head>
<body >
<div id="container"></div>
</body>
<script>
function throttle(func){
var timer;
return function(){
var context = this;
var args = arguments;
clearTimeout(timer);
timer = setTimeout(function(){
func.apply(context,args);
},1000);
}
}
function alertSomething(){
alert("您的鼠标正在移动");
};
document.getElementById("container").onmousemove = throttle(alertSomething);
</script>
</html>
下面我仔细解释一下这个节流函数。
函数利用闭包的形式存储了一个timer定时器变量,说实话我刚开始看别人在写这个节流函数的时候,也是不太容易懂,只是马马虎虎觉得是这样的,直到我亲自实现一遍,才明白。在这里建议亲自动手,丰衣足食~~
这个timer变量当然也可以写在全局作用域中,但是可能会跟全局作用域中的变量产生冲突,所以在这里用闭包的形式来提供,防止它污染全局作用域。(看好多人在这里用“污染”,我想可能是如果有很多像timer这样的变量都放在全局作用域中,到时候肯定容易与在全局作用域中常用的变量混淆。因为它毕竟只是在这个节流函数做定时器使用)。
然后就是throttle函数返回的函数了。在这个函数中,要保存好传进来的执行上下文this,和参数arguments。应为我们要注意的是setTimeout()函数中作用域是全局的,也就是setTimeout中的this指的是window,在这里这个执行上下文其实就是container对象,传入的参数就是鼠标移动这个事件的所有信息我们将这个container这个对象的鼠标移动事件函数重写成alertSomething这个函数。同时鼠标移动事件的信息也作为参数传入进去这一点也是我打印出他的相应信息后才恍然大悟,可能平时我们会理所当然的知道就是这样子的,但是为什么会这样子呢,我们知道了alertSomething这个函数的参数和执行上下文是怎么传进去的,那直接调用elementobj.onmousemove=function(){xxxxxx}这个函数的时候,上下文和参数是怎么传入进去的也应该是这样的原理吧。这是我的个人理解。
明白了上面的基本原理,我们再梳理一下节流函数发挥作用的过程:第一次调用这个节流函数的时候也就是第一次触发鼠标移动事件的时候,timer是没有的,所以clearTimeout(timer)清理的定时器也是没有的,但是等第二次触发鼠标移动事件的时候,鼠标移动事件的处理函数就是一直是throttle返回的函数了。首先会清理掉上次调用的时候的定时器,然后重新设置一个定时器。每次鼠标移动都是这样的处理过程,直到鼠标不再移动一秒钟后,定时器中的函数才被使用。
总之仔仔细细理解一下这个过程感觉真好!
但是如果我们需要自定义延迟的事件的话怎么办呢,下面我们可以再改进一下:
function throttle(func,delay){
var timer;
return function(){
var context = this;
var args = arguments;
clearTimeout(timer);
timer = setTimeout(function(){
func.apply(context,args);
},delay);
}
}
function dealMouseMove(){
alert("您的鼠标正在移动");
};
document.getElementById("container").onmousemove = throttle(dealMouseMove,500);
在这里感谢 Toobug 和 flowmemo 两位大神的指正,上面函数的功能更应该称之为debounce,也即是消除抖动的意思。前端技术中常用的throttle相当于一个频率控制器,让一段时间内快速触发很多次的事件处理程序可以只触发一定的次数, 而debounce不只是减少了触发次数,而且要满足一定的条件下才会触发。两者实现方法都是差不多的,叫法不一样而已,不能将两者割裂开来。
可以参考的相关网址:http://www.css88.com/archives/4648
可以参考的相关网址:http://www.alloyteam.com/2012/11/javascript-throttle/
JavaScript中函数节流的理解的更多相关文章
- JavaScript 中函数节流和函数去抖的讲解
JavaScript 中函数节流和函数去抖的讲解 我们都知道频繁触发执行一段js逻辑代码对性能会有很大的影响,尤其是在做一些效果实现方面,或者逻辑中需要进行后端请求,更是会导致卡顿,效果失效等结果,所 ...
- Javascript中函数的四种调用方式
一.Javascript中函数的几个基本知识点: 1.函数的名字只是一个指向函数的指针,所以即使在不同的执行环境,即不同对象调用这个函数,这个函数指向的仍然是同一个函数. 2.函数中有两个特殊的内部属 ...
- JavaScript中函数是不能重载原因
以前有一次写JS插件的时候,由于后台写习惯了,妄想在JS中写重载函数,可惜不能成功,原因花了一点时间记了下来 首先要理解重载的含义:函数返回值不同或者形式参数个数不同但函数名相同的函数 JavasSc ...
- JavaScript中函数作为另一个函数的参数的时候它存在于哪个作用域
一直对函数作为参数被传递进另外一个函数理解的不是很清除.先看下这段代码吧: function test(fn){ var bar = 1; fn(); } var bar = 99; test(fun ...
- JavaScript中函数函数的定义与变量的声明<基础知识一>
1.JavaScript中函数的三种构造方式 a.function createFun(){ } b.var createFun=function (){ } c.var createFun=new ...
- JavaScript中函数的形参和实参的实现原理剖析
我们都知道JS里面参数的传递是可以不一样的,比如我们有一个函数: <script type="text/javascript"> function one(a,b,c) ...
- JavaScript中函数的调用
JavaScript中函数的调用 制作人:全心全意 在JavaScript中,函数定义后并不会自动执行,要执行一个函数需要在特定的位置调用该函数,调用函数需要创建调用语句,调用语句包含函数名称和参数. ...
- JavaScript中函数的定义
JavaScript中函数的定义 制作人:全心全意 在JavaScript中,函数是由关键字function.函数名加一组参数以及置于大括号中需要执行的一段代码定义的.定义函数的基本语法格式如下: f ...
- javascript中函数声明、变量声明以及变量赋值之间的关系与影响
javascript中函数声明.变量声明以及变量赋值之间的关系与影响 函数声明.变量声明以及变量赋值之间有以下几点共识: 1.所有的全局变量都是window的属性 2.函数声明被提升到范围作用域的顶端 ...
随机推荐
- 用NSoup解析HTML
1.在NuGet程序包中添加NSoup包 public static void TestNSoup(string urlStr) { WebClient wc = new WebClient(); b ...
- 华山论剑之 PostgreSQL sequence (二)
rename 对 sequence 的影响 关联列与 sequence 后,即 sequence 属于该列后,drop 表或列时会自动 drop 相关 sequence. 但如果对表或列 rename ...
- Spring源码解析之八finishBeanFactoryInitialization方法即初始化单例bean
Spring源码解析之八finishBeanFactoryInitialization方法即初始化单例bean 七千字长文深刻解读,Spirng中是如何初始化单例bean的,和面试中最常问的Sprin ...
- php常见的危险函数
代码执行的危险函数 eval() 把字符串作为php代码执行 早期php一句话木马都用这个 <?php @eval($_POST['shell']);?> assert() 检查一个断言是 ...
- aria2 源码解析专题—— (一)基础架构
此文章是这个专题的开篇,由于初入 C++ 的大门,所以想着拿个项目来看看,凑巧有点基础,又想学习一下在unix上的编程,所以就找了 aria2 这个库来看看源码,希望能学到一些东西. 言归正传,今天把 ...
- BBS项目(二)
目录 BBS项目(二) ORM 创建相关表 表模型 修改admin样式 Simple-UI 注册表添加数据 注册forms类编写 注册功能前端搭建 头像实时显示功能实现 BBS项目(二) 可以在本地写 ...
- c++ set与unordered set的区别
c++ std中set与unordered_set区别和map与unordered_map区别类似,其底层的数据结构说明如下: 1.set基于红黑树实现,红黑树具有自动排序的功能,因此map内部所有的 ...
- 笔记软件-Obsidian(相关资料分享)
Obsidian(黑曜石) 是一个功能强大的知识管理软件,是一款功能强大的带有关系图谱功能的双向链笔记,它可基于纯文本Markdown文件的本地文件夹上运行 Obsidian是一个支持markdown ...
- Java案例——简单登录
public class UserLogin { public static void main(String[] args) { //1.定义两个字符串作为已知用户的姓名与密码 String Use ...
- _u32定义
驱动开发的原则: 能用__u32就最好用它,或者用u_int32_t之类的也可以,但不要直接用unsigned int等默认的数据类型.目的是让别人明白,你这个变量占多大内存. 原因: 1.你不能确定 ...