咱们常常会绑定一些继续触发的事件,比方 resize、scroll、mousemove 等等,如果事件调用无限度,会减轻浏览器累赘,导致用户体验差,咱们能够应用 debounce(防抖)和 throttle(节流)的形式来缩小频繁的调用,同时也不会影响理论的成果。
防抖的概念
触发事件后 n 秒后才执行函数,如果在 n 秒内触发了事件,则会从新计算函数执行工夫
防抖函数能够分为立刻执行,和非立刻执行两个版本
非立刻执行版本
- 非立刻执行版本
function debounce(fn, wait) {
let timer = null
return function () {
const context = this
const args = arguments
timer && clearTimeout(timer)
timer = setTimeout(() => {fn.apply(context, args)
}, wait)
}
}
此函数一开始不会马上执行,而是等到用户操作完结之后期待 wait 秒后才执行,如果在 wait 之内用户又触发了事件,则会从新计算
- 立刻执行版本
function debounce(fn, wait) {
let timer = null
return function () {
const args = arguments
const now = !timer
timer && clearTimeout(timer)
timer = setTimeout(() => {timer = null}, wait)
if (now) {fn.apply(this, args)
}
}
}
立刻执行就是触发事件后马上先执行一次,直到用户进行执行事件期待 wait 秒后再执行一次
咱们能够将两种版本合并成一种
/**
* @desc 函数防抖
* @param fn 函数
* @param wait 提早执行毫秒数
* @param immediate true 表立刻执行,false 示意非立刻执行
*/
function debounce(fn, wait, immediate) {
let timer = null
return function () {
const context = this
const args = arguments
timer && clearTimeout(timer)
if (immediate) {
const now = !timer
timer = setTimeout(() => {timer = null}, wait)
now && fn.apply(context, args)
} else {timer = setTimeout(() => {fn.apply(context, args)
}, wait)
}
}
}
节流的概念
间断触发事件但在 n 秒内只执行一次函数
对于节流有工夫戳和定时器两种版本
- 工夫戳版本
function throttle(fn, wait) {
var prev = 0
return function () {let now = Date.now()
let context = this
let args = arguments
if (now - prev > wait) {fn.apply(context, args)
prev = now
}
}
}
在继续触发事件的过程中,函数会立刻执行,用户在 wait 秒内不论执行多少次事件,都会期待 wait 秒后再执行。
- 定时器版本
function throttle(fn, wait) {
var timer = null
return function () {
const context = this
const args = arguments
if (!timer) {timer = setTimeout(() => {
timer = null
fn.apply(context, args)
}, wait)
}
}
}
在触发事件的过程中,不会立刻执行,并且每 wait 秒执行一次,在进行触发事件后还会再执行一次。
工夫戳版的函数触发是在时间段内开始的时候,而定时器版的函数触发是在时间段内完结的时候。
将两种形式合并
/**
* @desc 函数节流
* @param fn 函数
* @param wait 提早执行毫秒数
* @param type 1 表工夫戳版,2 表定时器版
*/
function throttle(fn, wait, type) {if (type === 1) {var prev = 0} else {var timer = null}
return function() {
const context = this
const args = arguments
if (type === 2) {if (!timer) {timer = setTimeout(() => {
timer = null
fn.apply(context, args)
}, wait)
}
} else if(type === 1) {const now = Date.now()
if (now - prev > wait) {fn.apply(context, args)
prev = now
}
}
}
}
参考链接