Merge pull request #5848 from pianruijie/feat/debounce-event

feat: debounce event
This commit is contained in:
hsm-lv 2022-12-05 17:29:18 +08:00 committed by GitHub
commit b9a2bd819d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 66 additions and 9 deletions

View File

@ -1,6 +1,8 @@
// https://json-schema.org/draft-07/json-schema-release-notes.html // https://json-schema.org/draft-07/json-schema-release-notes.html
import type {JSONSchema7} from 'json-schema'; import type {JSONSchema7} from 'json-schema';
import {ListenerAction} from './actions/Action'; import {ListenerAction} from './actions/Action';
import {debounceConfig} from './utils/renderer-event';
export interface Option { export interface Option {
/** /**
@ -592,6 +594,7 @@ export interface BaseSchemaWithoutType {
[propName: string]: { [propName: string]: {
weight?: number; // 权重 weight?: number; // 权重
actions: ListenerAction[]; // 执行的动作集 actions: ListenerAction[]; // 执行的动作集
debounce?: debounceConfig,
}; };
}; };
/** /**

View File

@ -2,10 +2,19 @@ import {ListenerAction, ListenerContext, runActions} from '../actions/Action';
import {RendererProps} from '../factory'; import {RendererProps} from '../factory';
import {IScopedContext} from '../Scoped'; import {IScopedContext} from '../Scoped';
import {createObject} from './object'; import {createObject} from './object';
import debounce from 'lodash/debounce';
export interface debounceConfig {
maxWait?: number;
wait?: number;
leading?: boolean;
trailing?: boolean;
}
// 事件监听器 // 事件监听器
export interface EventListeners { export interface EventListeners {
[propName: string]: { [propName: string]: {
debounce?: debounceConfig,
weight?: number; // 权重 weight?: number; // 权重
actions: ListenerAction[]; // 执行的动作集 actions: ListenerAction[]; // 执行的动作集
}; };
@ -16,7 +25,8 @@ export interface OnEventProps {
onEvent?: { onEvent?: {
[propName: string]: { [propName: string]: {
weight?: number; // 权重 weight?: number; // 权重
actions: ListenerAction[]; // 执行的动作集 actions: ListenerAction[]; // 执行的动作集,
debounce?: debounceConfig,
}; };
}; };
} }
@ -26,9 +36,11 @@ export interface RendererEventListener {
renderer: React.Component<RendererProps>; renderer: React.Component<RendererProps>;
type: string; type: string;
weight: number; weight: number;
debounce: debounceConfig | null,
actions: ListenerAction[]; actions: ListenerAction[];
executing?: boolean;
debounceInstance?: any;
} }
// 将事件上下文转成事件对象 // 将事件上下文转成事件对象
export type RendererEvent<T, P = any> = { export type RendererEvent<T, P = any> = {
context: T; context: T;
@ -86,14 +98,28 @@ export const bindEvent = (renderer: any) => {
if (listeners) { if (listeners) {
// 暂存 // 暂存
for (let key of Object.keys(listeners)) { for (let key of Object.keys(listeners)) {
const listener = rendererEventListeners.some( const listener = rendererEventListeners.find(
(item: RendererEventListener) => (item: RendererEventListener) =>
item.renderer === renderer && item.type === key item.renderer === renderer && item.type === key
); );
if (listener?.executing) {
listener?.debounceInstance?.cancel?.();
rendererEventListeners = rendererEventListeners.filter(
(item: RendererEventListener) =>
!(item.renderer === listener.renderer && item.type === listener.type));
rendererEventListeners.push({
renderer,
type: key,
debounce: listener.debounce || null,
weight: listener.weight || 0,
actions: listener.actions
});
}
if (!listener) { if (!listener) {
rendererEventListeners.push({ rendererEventListeners.push({
renderer, renderer,
type: key, type: key,
debounce: listeners[key].debounce || null,
weight: listeners[key].weight || 0, weight: listeners[key].weight || 0,
actions: listeners[key].actions actions: listeners[key].actions
}); });
@ -118,7 +144,7 @@ export async function dispatchEvent(
data: any, data: any,
broadcast?: RendererEvent<any> broadcast?: RendererEvent<any>
): Promise<RendererEvent<any> | void> { ): Promise<RendererEvent<any> | void> {
let unbindEvent = null; let unbindEvent: (() => void) | null | undefined = null;
const eventName = typeof e === 'string' ? e : e.type; const eventName = typeof e === 'string' ? e : e.type;
renderer?.props?.env?.beforeDispatchEvent?.( renderer?.props?.env?.beforeDispatchEvent?.(
@ -163,18 +189,46 @@ export async function dispatchEvent(
(prev: RendererEventListener, next: RendererEventListener) => (prev: RendererEventListener, next: RendererEventListener) =>
next.weight - prev.weight next.weight - prev.weight
); );
let executedCount = 0;
const checkExecuted = () => {
executedCount++;
if (executedCount === listeners.length) {
unbindEvent?.();
}
}
for (let listener of listeners) { for (let listener of listeners) {
await runActions(listener.actions, listener.renderer, rendererEvent); const {wait=100, trailing=true, leading=false, maxWait=10000} = listener?.debounce || {};
if (listener?.debounce) {
const debounced = debounce(
async () => {
await runActions(listener.actions, listener.renderer, rendererEvent);
checkExecuted();
},
wait,
{
trailing,
leading,
maxWait
}
);
rendererEventListeners.forEach(item => {
// 找到事件队列中正在执行的事件加上标识,下次待执行队列就会把这个事件过滤掉
if (item.renderer === listener.renderer && listener.type === item.type) {
item.executing = true;
item.debounceInstance = debounced;
}
});
debounced();
} else {
await runActions(listener.actions, listener.renderer, rendererEvent);
checkExecuted();
}
// 停止后续监听器执行 // 停止后续监听器执行
if (rendererEvent.stoped) { if (rendererEvent.stoped) {
break; break;
} }
} }
unbindEvent?.();
return Promise.resolve(rendererEvent); return Promise.resolve(rendererEvent);
} }