节流
所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数。节流会稀释函数的执行频率。
概念
按照设定的时间固定执行一次函数比如200ms一次。注意:固定就是在你mousemove过程中,执行这个节流函数,她一定是200ms(你设定的定时器延迟时间)内执行一次。没到200ms,一定会返回,没有执行回调函数的。
主要应用场景
scroll、touchmove
实现
思路:第一次先设定一个变量true,第二次执行这个函数时,会判断变量是否true,是则返回。当第一次的定时器执行完函数最后会设定变量为flase。那么下次判断变量时则为flase,函数会依次运行。
首次不执行
// 使用时间戳
function throttle(fn, delay=500){
let start = +new Date(),timer = 0;
return function(){
let cur = +new Date();
if(cur - start > delay){
timer = setTimeout(() => {
fn();
}, delay);
start = cur;
}
}
}
function throttle(fn, delay=500){
let timer = null;
return function (){
if(timer) return;
timer = setTimeout(() => {
fn();
timer = null;
}, delay);
}
}
首次执行
function throttle(fn, delay=500){
let last = 0;
return function (){
let cur = +new Date();
if(cur - last > delay){
fn();
last = cur;
}
}
}
合并版
/**
* @desc 函数节流
* @param func 函数
* @param wait 延迟执行毫秒数
* @param type 1 表时间戳版,2 表定时器版
*/
function throttle(func, wait ,type) {
if(type===1){
let previous = 0;
}else if(type===2){
let timeout;
}
return function() {
let context = this;
let args = arguments;
if(type===1){
let now = Date.now();
if (now - previous > wait) {
func.apply(context, args);
previous = now;
}
}else if(type===2){
if (!timeout) {
timeout = setTimeout(() => {
timeout = null;
func.apply(context, args)
}, wait)
}
}
}
}
防抖
所谓防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。
概念
抖动停止后的时间超过设定的时间时执行一次函数。注意:这里的抖动停止表示你停止了触发这个函数,从这个时间点开始计算,当间隔时间等于你设定时间,才会执行里面的回调函数。如果你一直在触发这个函数并且两次触发间隔小于设定时间,则一定不会到回调函数那一步。
主要应用场景
input验证、搜索联想、resize
实现
思路:首次运行时把定时器赋值给一个变量,第二次执行时,如果间隔没超过定时器设定的时间则会清除掉定时器,重新设定定时器,依次反复,当我们停止下来时,没有执行清除定时器,超过一定时间后触发回调函数。
非立即执行
// 使用时间戳
function debounce(fn, delay){
let start = +new Date(),timer = 0;
return function(){
let cur = +new Date();
window.clearTimeout(timer);
timer = setTimeout(() => {
fn();
}, delay);
start = cur;
}
}
function debounce(fn, delay=500){
let timer = null;
return function(){
if(timer) clearTimeout(timer);
timer = setTimeout(() => {
fn();
timer = null;
}, delay);
}
}
// 改变函数this指向
function debounce(func, wait) {
let timeout;
return function () {
let context = this;
let args = arguments;
if (timeout) clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(context, args)
}, wait);
}
}
非立即执行版的意思是触发事件后函数不会立即执行,而是在 n 秒后执行,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。
立即执行
function debounce(fn, delay = 200, atBegin = true) {
let timer = null, last = 0,during;
return function () {
let self = this, args = arguments;
var exec = function () {
fn.apply(self, args);
}
if (atBegin && !timer) {
exec();
atBegin = false;
} else {
during = Date.now() - last;
if (during > delay) {
exec();
} else {
if (timer) clearTimeout(timer);
timer = setTimeout(function () {
exec();
}, delay);
}
}
last = Date.now();
}
}
function debounce(func,wait) {
let timeout;
return function () {
let context = this;
let args = arguments;
if (timeout) clearTimeout(timeout);
let callNow = !timeout;
timeout = setTimeout(() => {
timeout = null;
}, wait)
if (callNow) func.apply(context, args)
}
}
立即执行版的意思是触发事件后函数会立即执行,然后 n 秒内不触发事件才能继续执行函数的效果。
合并版
/**
* @desc 函数防抖
* @param func 函数
* @param wait 延迟执行毫秒数
* @param immediate true 表立即执行,false 表非立即执行
*/
function debounce(func,wait,immediate) {
let timeout;
return function () {
let context = this;
let args = arguments;
if (timeout) clearTimeout(timeout);
if (immediate) {
var callNow = !timeout;
timeout = setTimeout(() => {
timeout = null;
}, wait)
if (callNow) func.apply(context, args)
}
else {
timeout = setTimeout(function(){
func.apply(context, args)
}, wait);
}
}
}