我的 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);
};
}
参考
这里是 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.
TLDR
Can I check about implementation about
event pooling
logic in react.
And I want to know aboutevent pooling
principle :)
问题
当我深入研究 React 文档时,我看到了大约 event pooling
。
所以,我很好奇什么是 event pooling
并且我研究了它。
现在我意识到 thread pooling
。所以它的工作方式类似。所以我做了一些伪event pooling
逻辑。
我想知道它是否有意义?
And any one who know about where
event pooling
implementation is inreact
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);
};
}
参考
这里是 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.