38.节流和防抖

在学习JavaScript的一些总结和经验,供大家参考和学习,同时也欢迎大家参与讨论。

矛盾:

  1. 用户频繁触发(点击),不断发起HTTP请求向后台发送数据,对服务器造成压力。

    比如:我们知道的浏览器事件window对象下的onresize、mousemove

    onresize、onscroll、keyup、keydown等等这些频繁的时间触发

区别: 防抖动是将多次执行变为最后一次执行,节流是将多次执行变成每隔一段时间执行。

http://bubkoo.com/2017/01/18/debouncing-throttling-explained-examples/

防抖:

场景:

  • 假设一个用户一直点击页面某个按钮,且每次点击的间隔小于wait(假设500ms),防抖的情况下只会调用最后一次点击触发的事件;(你尽管点击触发事件,反正我一定在最后一次点击事件触发n 秒后才执行)。

  • 用户注册时验证用户名是否被占用?现在很多网站为了提高用户体验,不会再输入框失去焦点的时候再去判断用户名是否被占用,而是在输入的时候就在判断这个用户名是否已被注册,这时就会频繁发起Ajax请求。

  • 搜索框的自动提示功能:如果我们希望当用户输入最后一个搜索词之后才发送Ajax,而不是输入一个就发送一次Ajax调用查询接口。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function debounce(fn, wait) { 
var timer = null;
return function () {
var context = this,
args = arguments;
clearTimeout(timer);
timer = setTimeout(function () {
fn.apply(context, args);
}, wait);
};
}
// ES6版本
const debounce = (func, wait = 500) => {
let timer = null;
return function(...args) {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, args);
}, wait);
}
}

需求:

我希望用户再第一次点击按钮的时候,就立即执行事件

在第一次执行完事件时,需要间隔wait ms之后,才能触发第二次点击事件(也就是第二次点击才能生效)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
function debounce(func, wait, immediate) {

var timeout, result;

var debounced = function () {
var context = this;
var args = arguments;

if (timeout) clearTimeout(timeout); // 如果持续触发事件,因为timeout不为null,所以清除定时器,一旦清除timeout,callNow就为false,自然就不会执行result
if (immediate) {
var callNow = !timeout; // 第一次进来timeout为null,所以callNow为true
timeout = setTimeout(function(){
timeout = null;
}, wait)
if (callNow) result = func.apply(context, args) // 第一次进来因为callNow为true,执行函数
}
else { // immediate为false,wait时间后触发func
timeout = setTimeout(function(){
func.apply(context, args)
}, wait);
}
return result;
};

debounced.cancel = function() {
clearTimeout(timeout);
timeout = null;
};

return debounced;
}

节流:

场景:

  • 调整浏览器大小,会连续触发onresize事件,假如在onresize事件处理程序内部有对DOM的操作,其高频率的更改可能会是浏览器崩溃。
  • 字母表滑动:例如微信好友右侧的字母滑动,当我们滑动的时候会连续触发touchmove事件。

共同点:持续触发事件;节流的目的就是要降低持续触发事件的频率,使每隔一小段时间,只执行一次事件。

一版:

用户点击触发事件的当前的时间,减去上一次点击的时间,如果大于传入的参数wait,就触发这次事件。

1
2
3
4
5
6
7
8
9
10
11
12
13
function throttle(func, wait) {
var context, args;
var previous = 0; // 用来保存上一次用户触发的时间
return function() {
var now = +new Date(); // 当前用户触发事件的时间
context = this;
args = arguments;
if (now - previous > wait) { // 当前用户触发事件的时间 - 上一次用户触发的时间 > wait
func.apply(context, args);
previous = now;
}
}
}

二版:

目的:

性能优化,节约计算机资源

参考:

https://github.com/mqyqingfeng/Blog/issues/22

https://github.com/mqyqingfeng/Blog/issues/26

https://yuchengkai.cn/docs/frontend/#%E9%98%B2%E6%8A%96

https://mp.weixin.qq.com/s/xLVCiq3CTRD6PkgtA5Zl7g

https://mp.weixin.qq.com/s/XLv2wyCPjjr1iu9JXyE4gw

https://mp.weixin.qq.com/s/7NjjScAHM4fQgTKB-6xurQ


文章标题: 38.节流和防抖
文章作者: 王奕聪,QQ:1301842163
许可协议: 知识共享许可协议
©署名-非商用-相同方式共享 4.0