我的 React 事件池伪示例有意义吗?

My react event pooling pseudo example makes sense?

TLDR

Can I check about implementation about event pooling logic in react.
And I want to know about event pooling principle :)

问题

当我深入研究 React 文档时,我看到了大约 event pooling
所以,我很好奇什么是 event pooling 并且我研究了它。

现在我意识到 thread pooling。所以它的工作方式类似。所以我做了一些伪event pooling逻辑。
我想知道它是否有意义?

And any one who know about where event pooling implementation is in react package.
Just comment to me please

伪事件池

EventPool 伪实现

class EventPool {
  private static instance: EventPool;
  private taskQueue: Event[] = [];
  private constructor() {
    this.taskQueue = [];
  }

  public static shared() {
    if (!EventPool.instance) {
      EventPool.instance = new EventPool();
    }
    return EventPool.instance;
  }

  enqueue = (event: Event) => {
    this.taskQueue = this.taskQueue.concat(event);
  };

  dequeue = (currentTarget: any) => {
    this.taskQueue = this.taskQueue.filter(
      (event: Event) => event.currentTarget === currentTarget
    );
  };

  clear() {
    // This function called before or after render 
    // (Commit -> Render -> EventPool.shared().clear()) or (Commit -> EventPool.shared().clear() -> Render) 
    this.taskQueue = this.taskQueue.filter((event) => event.isDone === true);
  }
}

关于persist

的事件伪实现
class Event {
  persist = () => {
    // This is executed before EventPool.shared.clear
    EventPool.shared().dequeue(this);
  };
}

参考

  1. Synthetic Event - React Document
  2. What's the meaning of Event Pooling?
  3. 진보된 쓰레드 풀링 기법 구현 - Korean

这里是 SyntheticEvent/EventPool 模式的一个非常简单的例子。显然在现实生活中,更好地尊重事件的行为会有点复杂,但这段代码必须阐明一些概念。

class SyntheticEvent {
    // all the following properties and methods are part of React's
    // synthetic event, but we'll skip it here in favor of simplicity

    // bubbles: boolean
    // currentTarget: DOMEventTarget
    // defaultPrevented: boolean
    // eventPhase: number
    // nativeEvent: DOMEvent
    // preventDefault(): void {}
    // isDefaultPrevented(): boolean { return true }
    // stopPropagation(): void {}
    // isPropagationStopped(): boolean { return true }
    // target: DOMEventTarget
    // timeStamp: number
    // type: string

    // for simplicity we'll consider here only 3 following properties
    isTrusted: boolean
    cancelable: boolean
    persist: () => void

    // this property helps to track status of each synthetic event
    status: 'POOLED' | 'PERSISTED' | 'IN_USE'

    constructor(status, onPersist: () => void) {
        this.status = status;
        this.persist = onPersist;
    }
}

class EventPool {
    private pool: SyntheticEvent[] = [];

    constructor(initialPoolSize: number) {
        // populating pool with pre-allocated events. We will try to re-use
        // them as much as possible to reduce GC load
        for(let i = 0; i < initialPoolSize; i++) {
            this.allocateNewEvent();
        }
    }

    pullEvent(nativeEvent): SyntheticEvent {
        const syntheticEvent = this.getEventFromPool();
        this.populateEvent(syntheticEvent, nativeEvent);
        return syntheticEvent;
    }

    tryPushEvent(syntheticEvent: SyntheticEvent): void {
        if(syntheticEvent.status !== 'PERSISTED') {
            this.clearEvent(syntheticEvent);
        }
    }


    private allocateNewEvent(): SyntheticEvent {
        const newEvent = new SyntheticEvent( 'POOLED', () => {
            newEvent.status = 'PERSISTED';
        });
        this.pool.push(newEvent);
        return newEvent;
    }

    private getEventFromPool() {
        let event = this.pool.find( e => e.status === 'POOLED' );
        if(!event) {
            event = this.allocateNewEvent();
        }

        return event;
    }

    /** Populates synthetic event with data from native event */
    private populateEvent(syntheticEvent: SyntheticEvent, nativeEvent) {
        syntheticEvent.status = 'IN_USE';
        syntheticEvent.isTrusted = nativeEvent.isTrusted;
        syntheticEvent.cancelable = nativeEvent.cancelable;
    }

    /** Sets all previously populated synthetic event fields to null for safe re-use */
    private clearEvent(syntheticEvent: SyntheticEvent) {
        syntheticEvent.status = 'POOLED';
        syntheticEvent.isTrusted = null;
        syntheticEvent.cancelable = null;
    }
}

// Usage
const mainEventPool = new EventPool(2);
smth.onClick = nativeEvent => {
    const syntheticEvent = mainEventPool.pullEvent(nativeEvent);
    userDefinedOnClickHandler(syntheticEvent); // <-- on click handler defined by user
    mainEventPool.tryPushEvent(syntheticEvent);
};

Event Pooling - React uses SyntheticEvent which is a wrapper for native browser events so that they have consistent properties across different browsers. The event handlers that we have in any react-app are actually passed instances of SyntheticEvent unless we use nativeEvent attribute to get the underlying browser event.

Wrapping native event instances can cause performance issues since every synthetic event wrapper that's created will also need to be garbage collected at some point, which can be expensive in terms of CPU time.

React deals with this problem by allocating a synthetic instance pool. Whenever an event is triggered, it takes an instance from the pool and populates its properties and reuses it. When the event handler has finished running, all properties will be nullified and the synthetic event instance is released back into the pool. Hence, increasing the performance.