Open BetaSu opened 2 years ago
/**
* 函数防抖:短时间内多次触发同一事件,只执行第一次或者最后一次,中间的不执行
*/
/**
* @param {function} func 事件响应函数
* @param {number} delay 延迟时间
* @param {boolean} imme 是否立即执行
*/
function debounce(func, delay, imme) {
var timer
return function () {
var _self = this,
_args = arguments,
res
if (timer) clearTimeout(timer)
if (imme) {
/**
* 触发事件后立即执行,指定时间内不再执行,若指定时间内再次触发则重置定时
* 例如,点击按钮进行提交
*/
if (!timer) res = func.apply(_self, _args)
timer = setTimeout(function () {
timer = null
}, delay)
} else {
/**
* 触发事件指定时间后执行,若指定时间内再次触发则重置定时
* 例如,输入框内容判断
*/
timer = setTimeout(function () {
res = func.apply(_self, _args)
}, delay)
}
return res
}
}
/**
* 函数节流:一段时间内多次触发同一事件,但只按指定时间间隔执行
* 例如,图片懒加载
*/
/**
* @param {function} func 事件响应函数
* @param {number} delay 间隔时间
*/
/**
* 通过计算时间间隔
* 问题:最后一次触发不会执行
*/
function throttle(func, delay) {
// var begin = new Date().getTime()
var begin = 0
return function () {
var _self = this,
args = arguments,
res,
now = new Date().getTime()
if (now - begin > delay) {
res = func.apply(_self, args)
begin = now
}
return res
}
}
/**
* 通过定时器
* 问题:第一次触发不会立即执行
*/
function throttle(func, delay) {
var timer
return function () {
var _self = this,
_args = arguments,
res
if (!timer) {
timer = setTimeout(function () {
timer = null
res = func.apply(_self, _args)
}, delay)
}
return res
}
}
/**
* 最终版:通过定时器 + 计算时间间隔
*/
function throttle(func, delay) {
var begin = 0,
timer
return function () {
var _self = this,
_args = arguments,
res,
now = new Date().getTime()
if (now - begin >= delay) {
if (timer) {
clearTimeout(timer)
timer = null
}
begin = now
res = func.apply(_self, _args)
} else if (!timer) {
timer = setTimeout(function () {
timer = null
res = func.apply(_self, _args)
}, delay)
}
return res
}
}
维护一个计时器,在规定的delay时间后触发函数,在delay时间内再次触发的话,就会取消之前的计时器而重新设置。这样一来,只有最后一次操作能被触发。
function fn(...arg) {
console.log (arg[0]); //输出events对象
}
//防抖-频繁触发,只有最后一次会生效
function debounce(fn, delay=500){
//定时器初始化
let timer = null
//通过闭包的方式,来获取定时器,同时返回onclick调用的函数
return function(){
timer && clearTimeout(timer)
timer = setTimeout(()=>{
//这里的arguments为外层的arguments(包含了event事件对象),箭头函数没有自己的arguments
fn(arguments)
}, delay)
}
}
document.getElementById('btn').onclick = debounce(fn, 1000)
函数执行一次后,只有在大于设置的执行周期后才会执行第二次。持续触发事件时,保证一定时间段内只调用一次事件处理函数。
function throttle(fn, delay){
//时间初始化
let oldTime = 0
return function(){
lastTime = Date.now()
if((lastTime - oldTime)> delay){
fn(arguments)
//记录触发的时间作为oldTime
oldTime = lastTime
}
}
}
document.onscroll = throttle(fn, 1000)
节流旨在时间段内控制触发的频率,防抖则是旨在时间段内只触发最后一次。
export function debounce<Args extends any[], F extends (...arg: Args) => any>(
fn: F,
wait: number = 500,
immediate: boolean = false
) {
let timer: ReturnType<typeof setTimeout> | null = null;
return function (this: ThisParameterType<F>, ...args: Parameters<F>) {
const context = this;
if (timer) {
clearTimeout(timer);
}
if (immediate) {
if (!timer) {
fn.apply(context, args);
}
timer = setTimeout(() => {
timer = null;
}, wait);
} else {
timer = setTimeout(() => {
fn.apply(context, args);
}, wait);
}
};
}
export function throttle<Args extends any[], F extends (...args: Args) => any>(
fn: F,
wait: number = 500
) {
let canRun = true;
return function (this: ThisParameterType<F>, ...args: Args) {
if (!canRun) {
return;
}
const context = this;
canRun = false;
setTimeout(() => {
fn.apply(context, args);
canRun = true;
}, wait);
};
}
首先我们说说防抖和节流的概念,防抖节流都是稀释执行频率的方式
防抖
function debounce(fn, delay=500){
let timer = null
//通过闭包的方式,来获取定时器,同时返回onclick调用的函数
return function(){
timer && clearTimeout(timer)
timer = setTimeout(()=>fn(), delay)
}
}
节流
function throttling(fn, delay=500) {
let last = 0;
return (...args) => {
const now = Date.now();
if (now > last + delay) {
last = now;
fn.apply(this, args);
}
};
}
/**
* **防抖**
* 限制给定时间内连续触发的效果
* @param {Function} fn
* @param {number} time 防抖时间间隔
* @param {boolean} immediate 是否立即执行,默认false
* @returns {Function}
*/
export const debounce = function (fn, time, immediate = false) {
let timeOut = null;
let startTime = 0;
return function wrapThrottle(...args) {
let delayTime = time;
if (timeOut) window.clearTimeout(timeOut);
if (immediate && !timeOut) delayTime = startTime + time < Date.now() ? 0 : time;
const callback = () => {
fn.apply(this, args)
startTime = Date.now();
timeOut = null;
}
timeOut = window.setTimeout(callback, delayTime)
}
}
使用场景:监听鼠标移动事件;
/**
* **节流**
* 只能在限制的时间间隔触发
* @param {Function} fn
* @param {number} time
* @param {boolean} immediate 第一次是否立即执行,默认true
* @returns
*/
export const throttling = function (fn, time, immediate = true) {
let timeOut = null;
let startTime = 0;
return function wrapThrottle(...args) {
let delayTime = time;
if (timeOut) return;
if (immediate) delayTime = startTime + time - Date.now();
const callback = () => {
fn.apply(this, args)
startTime = Date.now();
timeOut = null;
}
timeOut = window.setTimeout(callback, delayTime)
}
}
使用场景:向后台更新用户输入;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>防抖节流</title>
</head>
<body>
<button onclick="ClickHandle(debounce, 2000)">防抖</button>
<button onclick="ClickHandle(throttle, 2000)">节流</button>
<script>
let timer = null
let timer1 = null
let count = 0
function ClickHandle(fn, delay){
fn(function(t){
console.log(t)
}, delay)()
}
function debounce(fn, delay){
count += 1
console.log('执行防抖函数'+count+'次', delay)
return function(){
timer && clearTimeout(timer)
timer = setTimeout(()=>{
count = 0
fn('执行程序')
}, delay)
}
}
function throttle(fn, delay){
count += 1
return function(){
let now = Date.now()
if((now - timer1)> delay){
fn('节流-2s执行一次')
timer1 = now
}
}
}
</script>
</body>
</html>
防抖,顾名思义,防止抖动,以免把一次事件误认为多次,敲键盘就是一个每天都会接触到的防抖操作。
防抖重在清零 clearTimeout(timer)
function debounce (f, wait) {
let timer
return (...args) => {
clearTimeout(timer)
timer = setTimeout(() => {
f(...args)
}, wait)
}
}
节流,顾名思义,控制水的流量。控制事件发生的频率,如控制为1s发生一次,甚至1分钟发生一次。与服务端(server)及网关(gateway)控制的限流 (Rate Limit) 类似。
节流重在开关锁 timer=null
function throttle (f, wait) {
let timer
return (...args) => {
if (timer) { return }
timer = setTimeout(() => {
f(...args)
timer = null
}, wait)
}
}
这是来自QQ邮箱的假期自动回复邮件。 您好,我最近正在休假中,无法亲自回复您的邮件。我将在假期结束后,尽快给您回复。
要实现的功能
请按照以下顺序回答该问题:
1.什么是防抖和节流? 2.应用场景有哪些? 3.手写防抖和节流,简单版本即可。
代码示例
最佳答案评选标准
最佳答案
悬赏中,欢迎作答...
答题同学须知
答题规范:请在
一次评论
中完成作答,后续修改也请编辑该评论,而不是追加新的评论评选标准:最佳答案由
围观同学
的 👍 和卡颂共同决定评选时间:一般是问题发布24小时后评选,如果问题发布当天回答数较少,问题悬赏金额可能增加,同时悬赏时间也会增加
围观同学须知
对于你满意的答案,请不要吝惜你的 👍,这是评选最佳答案的依据
非答题的评论
会被删除,问题相关讨论请在赏金猎人群中进行