函数防抖
什么是防抖?
某些时候某些操作是高频触发的,但是其实触发一次就好了,比如我们短时间内多次请求接口,那么我们不应该每次点击都去请求接口,应该只做一次就好。再比如说监听输入框的输入,不应该每次都去触发监听,应该是用户完成一段输入后在进行触发。
所以,我们的思路就是:1、对于在事件被触发 N 秒后再执行的回调(延迟执行);2、如果在这 N 秒内再次触发事件,那么就重新开始计时
var oBox = document.getElementsByClassName("box")[0];var t = null; // 保存定时器oBox.onclick = function () {// 每次都先清除定时器clearTimeout(t);// 然后立马赋值,当 1 秒频繁触发事件的时候,第 9 行是不会执行的!t = setTimeout(function () {console.log(1);}, 1000);};
这样就实现了一个简单的防抖操作,可是我觉得还是不够完美,因为当我们第一次点击oBox的时候也会延迟执行,那我们就可以抽离一个防抖函数,实现自定义是否第一次就延迟执行。
var oBox = document.getElementsByClassName("box")[0];oBox.onmouseover = debounce(handleEvent, 1000, true);function handleEvent() {console.log(1);}function debounce(fn, time, triggleNow) {var t = null;var res;return function () {var _self = this;var arg = arguments;if (t) {// 每次都先清除定时器clearTimeout(t);}// 如果 triggleNow 为 true,就表示第一次的时候不需要延迟执行if (triggleNow) {// 如果 t 是 null 的话,exec 就是 truevar exec = !t;// t 立马被赋值为定时器,1 秒内再次触发事件的时候 !t 就为 false 了t = setTimeout(function () {// 1 秒后再把 t 赋值为 null,下次 !t 又变成 true 了t = null;}, time);// 这里比 setTimeout 先执行if (exec) {res = fn.apply(_self, arguments);}} else {// 这里和我们最开始写的片段是一样的!t = setTimeout(function () {res = fn.apply(_self, arguments);}, time);}return res;};}
函数节流
函数节流和函数防抖基本类似,唯一的区别就是:防抖函数在一段时间内频繁触发事件只会执行一次,节流函数在一段时间内频繁触发事件会定时执行一次。
var oInput = document.getElementsByClassName("search")[0];oInput.oninput = throttle(handleEvent, 1000);function handleEvent() {console.log("success");}function throttle(fn, delay) {var t = null;var begin = new Date().getTime(); // 调用函数的时间return function () {var _self = this;var args = arguments;var cur = new Date().getTime(); // 触发触发的时间clearTimeout(t); // 先清除定时器// 如果 当前时间-调用函数的时间 >= 设置的延迟时间// 就表示时间到了,可以立即执行if (cur - begin >= delay) {fn.apply(_self, args);// 将调用函数的时间重新赋值begin = cur;} else {// 否则就是时间还没到,只能延迟执行// 然后立即赋值定时器t = setTimeout(function () {fn.apply(_self, args);}, delay);}};}
或者也可以用一个变量来控制:
function thorttle(fn, wait) {let timer;return function () {let _this = this;let args = arguments;// 如果 timer 为定时器的 id ,是不会进入 if 内的if(!timer) {timer = setTimeout(function(){// 延迟之后 timer 变为 nulltimer = null;fn.apply(_this, args)}, wait)}}}
