一、一种现象

有一个input框,每次输入都要触发一次change事件,其实这大可不必,比如我输入 “上海” 两个字,竟然触发了9次。

const input = document.querySelector('input')input.oninput = function() {console.log(this.value)}

 假如每次change都会和后端发生一次交互,这个性能就会很惨。

怎么才能让这个次数变的少?

二、防抖

用户触发事件过于频繁,只要最后一次事件的操作。比如我们可以设置500ms,只要在500ms内你一直还在输入,也就是说你的停顿是少于500ms的,那么就不触发change事件里的复杂逻辑。在执行复杂逻辑之前就把定时器清理掉。

const input = document.querySelector('input')let t = nullinput.oninput = function() {if (t !== null) {clearTimeout(t)}t = setTimeout(() => {// 用一句打印代替复杂的业务逻辑console.log(this.value)}, 500)}

三、代码改进

上面的代码有2个大毛病:

  1. let t是个全局变量;
  2. 防抖的逻辑 if (t !== null) 和 业务逻辑都混在一起了。

用闭包来改进这段代码

上面,在调用debounce的时候,第一个参数是传递一个函数,

我们传的是一个() => {console.log(this.value)} ,这里的this是window,但是我们想要的是input。

所以,可以用call的方式来

const input = document.querySelector('input')input.oninput = debounce(function() { // 这里如果用箭头函数,还是指向window,不能用箭头函数// 业务逻辑,用一个打印代替console.log(this.value)}, 500)function debounce(fn, delay) {let t = nullreturn function() {if (t !== null) {clearTimeout(t)}t = setTimeout(() => {// 执行业务逻辑,这里的this就是input 事件对象console.log('this: ', this)fn.call(this)}, delay)}}

四、节流

有一种情形,滚动事件,会执行很多次。

window.onscroll = function() {console.log('---------')}

 你看,不到一秒钟随便滚动一下就是100多次。

防抖:只执行最后一次;

节流:控制执行次数;让耗性能的方法减少执行次数;

和防抖是一样的写法

window.onscroll = throttle(() => {// 这里是业务逻辑,this:windowconsole.log('..........')}, 500)function throttle(fn, delay) {let flag = truereturn function() {if (flag) {setTimeout(() => {fn.call(this)flag = true}, delay)}flag = false}}