createFilterWrapper
js
/**
* @internal
*/
export function createFilterWrapper<T extends AnyFn>(filter: EventFilter, fn: T) {
function wrapper(this: any, ...args: ArgumentsType<T>) {
return new Promise<Awaited<ReturnType<T>>>((resolve, reject) => {
// make sure it's a promise
Promise.resolve(filter(() => fn.apply(this, args), { fn, thisArg: this, args }))
.then(resolve)
.catch(reject);
});
}
return wrapper;
}
createFilterWrapper
返回的函数wrapper
就是被eventFilter
处理过的函数,比如传入的fn希望被节流,当filter
是throttleFilter
,那么wrapper
就是一个节流的函数。
// 创建一个节流函数(只创建一次)
js
const throttledFn = useThrottleFn(() => {
console.log('throttled function');
});
// 多次调用这个节流函数(每次调用会创建一个新Promise,但执行会受到节流控制)
js
throttledFn();
throttledFn();
throttledFn();
也就是当执行 throttledFn()就会执行 filter(() => fn.apply(this, args), { fn, thisArg: this, args })
本质上这个filter
才是最终的「节流了的函数」,即 throttledFn <==> filter
和lodash一样节流/防抖,如何用createFilterWrapper实现呢?
如const fn = _.debounce(fn, 200, { maxWait: 1000 })
,使用createFilterWrapper 如下:
js
fn = createFilterWrapper(
debounceFilter(200, { maxWait: 1000 }),
fn,
);
throttleFilter
js
// throttleFilter函数内返回的filter
const filter: EventFilter = (_invoke) => {
const duration = toValue(ms);
const elapsed = Date.now() - lastExec;
const invoke = () => lastValue = _invoke();
clear();
if (duration <= 0) {
lastExec = Date.now();
return invoke();
}
if (elapsed > duration && (leading || !isLeading)) {
lastExec = Date.now();
invoke();
} else if (trailing) {
lastValue = new Promise((resolve, reject) => {
lastRejector = rejectOnCancel ? reject : resolve;
timer = setTimeout(() => {
lastExec = Date.now();
isLeading = true;
resolve(invoke());
clear();
}, Math.max(0, duration - elapsed));
});
}
if (!leading && !timer) timer = setTimeout(() => isLeading = true, duration);
isLeading = false;
return lastValue;
};