前言
前面已经对防抖和节流有了介绍,这篇主要看lodash是如何将防抖和节流合并成一个函数的。
初衷是深入lodash,学习它内部的好代码并应用,同时也加深节流防抖的理解。这里会先从防抖开始一步步往后,由简入繁,直到最后实现整个函数。
这里纯粹自己的理解,以及看了很多篇优质文章,希望能加深对节流防抖的理解,如果有不同意见或者看法,欢迎大家评论。
原理
前面虽然已经介绍过防抖和节流原理,这里为了加深印象,再搬过来。
防抖的原理:在wait时间内,持续触发某个事件。第一种情况:如果某个事件触发wait秒内又触发了该事件,就应该以新的事件wait等待时间为准,wait秒后再执行此事件;第二种情况:如果某个事件触发wait秒后,未再触发该事件,则在wait秒后直接执行该事件。
通俗点说:定义wait=3000,持续点击按钮,前后点击间隔都在3秒内,则在最后一次点击按钮后,等待3秒再执行func方法。如果点击完按钮,3秒后未再次点击按钮,则3秒后直接执行func方法。
节流的原理:持续触发某事件,每隔一段时间,只执行一次。
通俗点说,3 秒内多次调用函数,但是在 3 秒间隔内只执行一次,第一次执行后 3 秒 无视后面所有的函数调用请求,也不会延长时间间隔。3 秒间隔结束后则开始执行新的函数调用请求,然后在这新的 3 秒内依旧无视后面所有的函数调用请求,以此类推。
简单来说:每隔单位时间( 3 秒),只执行一次。
代码分析
一、引入代码部分
首先看源码最前方的引入。
import isObject from './isObject.js'
import root from './.internal/root.js'
isObject方法,直接拿出来,
function isObject(value) {
const type = typeof value;
return value != null && (type === "object" || type === "function");
}
root的引入主要是window。为了引出window.requestAnimationFrame
。
二、requestAnimationFrame代码
window.requestAnimationFrame()
告诉浏览器希望执行动画并请求浏览器在下一次重绘之前调用指定的函数来更新动画,差不多 16ms 执行一次。
lodash这里使用requestAnimationFrame
,主要是用户使用debounce函数未设置wait的情况下使用requestAnimationFrame
。
const useRAF = (!wait && wait !== 0 && typeof window.requestAnimationFrame === 'function')
function startTimer(pendingFunc, wait) {
if (useRAF) {
window.cancelAnimationFrame(timerId)
return window.requestAnimationFrame(pendingFunc)
}
return setTimeout(pendingFunc, wait)
}
function cancelTimer(id) {
if (useRAF) {
return window.cancelAnimationFrame(id)
}
clearTimeout(id)
}
由代码const useRAF = (!wait && wait !== 0 && typeof window.requestAnimationFrame === 'function')
不难看出,函数未传入wait并且window.cancelAnimationFrame函数存在这两种情况下操作window.requestAnimationFrame
三、由简入繁输出防抖函数
首先,我们来看下lodash debounce API
这部分参数内容就直接摘抄在下方:- func (Function): 要防抖动的函数。
- [wait=0] (number): 需要延迟的毫秒数。
- [options=] (Object): 选项对象。
- [options.leading=false] (boolean): 指定在延迟开始前调用。
- [options.maxWait] (number): 设置 func 允许被延迟的最大值。
- [options.trailing=true] (boolean): 指定在延迟结束后调用。