现代网页的实现上,会有很多交互上的优化,比如常见的 滚动加载 ,输入联想 等等。他们的实现思路很简单,以滚动加载而言,无非就是去是增加一个滚动的事件监听,每次滚动判断当前的元素是否已经滚动到了用户的可视区,然后根据判断结果来决定是否来加载相关数据。 输入联想也类似,无非就是修改一下监听的事件类型,和判断的相关逻辑。

前端交互的优化上,我们总是需要需要事件监听来知道用户进行了什么操作,从而设定页面给出怎样的反应。但本文主要的内容不是讲如何具体的实现某个交互,而是对交互实现的依赖的事件监听那部分的优化。

滚动加载图片的例子

1
2
3
4
5
6
7
8
var onScroll = function() {
// 这里判断当前的 img 元素是否已经滚动到了用户的可视区
// 根据判断结果来决定是否来加载相关数据
// 注:img 元素当设置 src 属性值后会产生一个 http 的请求,加载图片
}; window.addEventListener('scroll',onScroll ,false);

这样理论上就实现了图片的滚动加载或者说是按需加载,懒加载等等。

这样的实现乍看没有任何问题,但在实际的场景中,问题还是很严重的。

如下:

很明显,当你在 codepen 中滚动鼠标的时候,显示的数字蹭蹭蹭的加大, 这个数字就是过程中,浏览器触发 scroll 事件的数字, 可以看出,浏览器触发 scroll 事件是很频繁的。

所以,回到上面提出的问题中,因为浏览器触发 scroll 会很平凡, 也就意味着事件的监听回调函数 onScroll 会被很频繁的执行。这就是问题之所在,且不说我们的 onScroll 里面的逻辑可能会是大量的计算。如此频繁的计算就算可以很轻松的被完成,结果也是没有意义的。所以我们要在这里来优化代码,倒不是优化 onScroll 本省,而是想办法让 onScroll 执行的次数可以减少。

函数节流

在原本的逻辑中,假设在滚动条连续的滚动中,浏览器每 10ms 触发一次scroll 事件,就意味着浏览器每 10ms 就要去执行一次 onScroll,如果想让 onScroll 不那么频繁的被执行,怎么办?

很明显,想去改动 scroll 触发的频率在前端这一层面上肯定是不行,因为他们浏览器自身的设定。那么是否可以在触发 scroll 事件之后,不直接调用 onScroll 函数从而进行优化呢?比如,假设scroll 事件持续触发,我们让 onScroll 函数每 250ms 触发。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var throttle = function() {
var previous = 0; // 初始设置上一次调用 onScroll 函数时间点为 0。
var timeout;
var wait = 250; // 该变量表示执行 onScroll 函数的间隔时间。
// 返回一个函数 ,该函数在每次触发 scroll 事件时,真正调用的函数。
return function() {
var now = Date.now(); // 记录下当前触发 scroll 的时间
var remaining = wait - (now - previous); // 持续的滚动过程中,计算得到调用 onScroll 的甚于时间
if (remaining <= 0) {
if (timeout) {
clearTimeout(timeout)
}
previous = now;
timeout = null;
onScroll();
} else if(!timeout) { // 初始或者非持续滚动(滚动动作的时间小于 250ms ),设定一个定时器。
timeout = setTimeout(onScroll, wait);
}
}
}; // 注意这里的调用方式
window.addEventListener('scroll',throttle() ,false);

这样调用是不会有结果的

1
window.addEventListener('scroll',throttle ,false);

上述的代码旨在说明实现函数节流的思路,著名的 underscore.js 和 lodash 都有节流方法的实现。

输入联想的例子

当你在使用 google 搜索内容的时候,有些关键词输入到一般,谷歌会展示一个可选列表,是根据你当前输入的内容作出的一个猜测联想,如果有中目标的联想,你就可以不需要输入接下来的内容,直接选择自动补全就好。

这种场景下,我们一般是去监听用户的 onKeyRress 或者 onKeyUp 等等键盘事件。在当用户输入一些文字的时候,我们一监听到键盘事件就将用户当前输入的内容去发送一个 ajax 查询请求显然是不行的。那么在节流函数内部去调用 ajax 请求呢?

在这种场景下,其实函数节流也是不合适,因为,函数节流只是减小了函数执行的在事件触发过程中频率,将原来可能调用1000次减少到调用100次。然而对输入联想的场景来说,只要用户还在触发键盘事件,那么发送请求就是没有意义的。

所以,我们现在需要的一种实现是应该是在用户停止键盘事件一段时间后,去发送一个请求。

比如应该这么设计这个过程,用户在输入,用户输入有所停顿(也就是不再触发键盘事件),当这个事件大于 250ms 之后,去触发一个查询请求。 如果用户输入停顿的时间小于 250ms,不去发送查询请求。

电梯模型

输入联想的执行过程,应该和生活中的电梯执行过程是一样的。
比如,当你正在座电梯,当电梯门正要关闭的时候,这是有一个同学又冲过来,按了一下电梯的按钮,这个电梯门会打开然后等待一定的时间,如果在等待的过程中,又有另外一位同学过来按了按钮,之前等待的时间清零,继续等待一定的时间,直到在等待的时间中,不在有别的人去按按钮。门才会关闭,然后上下运行。

函数去抖

了解这个过程之后,来简单的实现下这个过程。

1
2
// 如下搜索控件
<input type="search" name="search" />
1
2
3
4
5
6
7
8
9
10
11
12
13
14
var sendAjax = function(obj) {
// 发送请求
};
var debounce = function() {
var wait = 2500;
var timeout;
return function () {
if (timeout) clearTimeout(timeout);
timeout = setTimeout(sendAjax, wait);
}
};
var input = document.querySelector('input[name=search]'); input.addEventLister('keyup', debounce(), false);

总结

函数节流和函数去抖的使用场景略有不同。

函数节流:在事件触发过程中,减小相关回调函数的执行频率。
函数去抖:在事件触发结束后一定时间后去执行事件回调函数,如果在这一定时间内又触发了相关事件,则不去触发事件回调函数,下一次执行事件回调函数时间仍是确定的一定时间。

相关文章和代码

浅析 JavaScript 的函数节流和去抖的更多相关文章

  1. JS 函数节流和去抖

    1.什么是节流和去抖? 节流.就是拧紧水龙头让水少流一点,但是不是不让水流了.想象一下在现实生活中有时候我们需要接一桶水,接水的同时不想一直站在那等着,可能要离开一会去干一点别的事请,让水差不多流满一 ...

  2. hover时显示可跟随鼠标移动的浮动框,运用函数节流与去抖进行优化

    在很多笔试面试题中总能看到js函数去抖和函数节流,看过很多关于这两者的讨论,最近终于在一个需求中使用了函数去抖(debounce)和函数节流(throttle). 需要完成的效果是,鼠标在表格的单元格 ...

  3. JavaScript 中函数节流和函数去抖的讲解

    JavaScript 中函数节流和函数去抖的讲解 我们都知道频繁触发执行一段js逻辑代码对性能会有很大的影响,尤其是在做一些效果实现方面,或者逻辑中需要进行后端请求,更是会导致卡顿,效果失效等结果,所 ...

  4. 深入理解JS函数节流和去抖动

    一.什么是节流和去抖? 1.节流 节流就是拧紧水龙头让水少流一点,但是不是不让水流了.想象一下在现实生活中有时候我们需要接一桶水,接水的同时不想一直站在那等着,可能要离开一会去干一点别的事请,让水差不 ...

  5. 浅谈javascript的函数节流

    什么是函数节流? 介绍前,先说下背景.在前端开发中,有时会为页面绑定resize事件,或者为一个页面元素绑定拖拽事件(其核心就是绑定mousemove),这种事件有一个特点,就是用户不必特地捣乱,他在 ...

  6. javascript之函数节流

    对于高频率的事件触发,为了优化页面性能,我们一般会对其做函数节流.比如: resize.keydow.scroll事件等.用户的频繁操作,会导致事件高频率的执行,这样会出现页面抖动啊.频繁调接口啊等问 ...

  7. JavaScript中函数节流的理解

    函数节流的原理 函数节流,就是对会频繁触发的函数事件做一些限制,让这些函数可以在每隔一定的时间或者每次满足一定的条件下再触发.一般我们会给他起一个名字throttle.也就是节流的意思.一般这样的函数 ...

  8. JavaScript之 函数节流(Throttling) 与 防抖(Debounce)

    Throttling:在监听鼠标移动事件.盒子滚动事件等使用节流技术能节省性能消耗 /** * 节流函数(每隔t执行一次) */ function Throttling(fn, t) { const ...

  9. JavaScript 函数节流和函数去抖应用场景辨析

    概述 也是好久没更新 源码解读,看着房价蹭蹭暴涨,心里也是五味杂陈,对未来充满恐惧和迷茫 ...(敢问一句你们上岸了吗) 言归正传,今天要介绍的是 underscore 中两个重要的方法,函数节流和函 ...

随机推荐

  1. Sublime 插件安装

    转http://www.cnblogs.com/Rising/p/3741116.html

  2. 启动Activity,传递参数最佳实践

    优化后的好处不言而喻,OtherActivity中所需要的参数都在方法参数中体现,减少了交流询问的成本. (1)MainActivity.java OtherActivity.openActivity ...

  3. png透明图片

    2. JS处理 使用DD_belatedPNG(http://www.dillerdesign.com/experiment/DD_belatedPNG/),可以很简单的对界面上所有的透明图片进行同一 ...

  4. DES、AES、TEA加密算法的比较

    1.     DES算法介绍: DES算法具有对称性, 既可以用于加密又可以用于解密.对称性带来的一个很大的好处在于硬件实现, DES 的加密和解密可以用完全相同的硬件来实现.DES 算法的明文分组是 ...

  5. 【Xamarin挖墙脚系列:Xamarin 上台讲述PPT呵呵呵】

    http://pan.baidu.com/s/1kUrwQft

  6. 关于ViewPager被嵌套在ScrollView中不显示的问题

    关于ViewPager被嵌套在ScrollView中不显示的问题 进入全屏 ScrollView 嵌套ViewPager,要不是业务需求这样,估计没人愿意这么干!因为这种方式,会问题多多,简单百度一下 ...

  7. python刷取CSDN博文访问量之一

    python刷取CSDN博文访问量之一 作者:vpoet 注:这个系列我只贴代码,代码不注释.有兴趣的自己读读就懂了,纯属娱乐,望管理员抬手 若有转载一定不要注明来源   #coding=utf-8 ...

  8. hdu1172猜数字(暴力枚举)

    猜数字 Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submi ...

  9. sendto() 向广播地址发包返回errno 13, Permission denied错误

    http://blog.csdn.net/guanghua2_0beta/article/details/52483916 sendto() 向广播地址发包返回errno 13, Permission ...

  10. 求高精度幂(java)

    求高精度幂 时间限制:3000 ms  |  内存限制:65535 KB 难度:2   描述 对数值很大.精度很高的数进行高精度计算是一类十分常见的问题.比如,对国债进行计算就是属于这类问题. 现在要 ...