我有一个带有一些代码的React组件,如下所示:
class MyComponent extends React.Component {
// ...
trackStats = false
componentDidMount() {
this.monitorActivity()
}
componentWillUnmount() {
this.trackStats = false
}
async monitorActivity() {
this.trackStats = true
while (this.trackStats && this.elRef.current) {
// elRef is a React ref to a DOM element rendered in render()
await Promise.race([
nextEvent(this.elRef.current, 'keydown'),
nextEvent(this.elRef.current, 'click'),
nextEvent(this.elRef.current, 'mousemove'),
nextEvent(this.elRef.current, 'pointermove'),
])
this.logUserActivity()
}
}
logUserActivity() {
// ...
}
render() { /* ... */ }
}
const nextEvent = (target, eventName) => new Promise(resolve => {
target.addEventListener(eventName, resolve, { once: true })
})
问题是,如果卸载了此组件,则添加到
this.elRef.current
引用的DOM元素上的事件处理程序将保留在内存中,因为用户将不再与DOM中不再存在的元素进行交互。因此,while循环将停留在等待下一个事件的发生,而该事件将永远不会发生,并且由于while循环仍在等待最后一个事件,因此我相信这将导致
MyComponent
的实例在内存中泄漏。还是引擎某种程度上足以解决这个问题?如果我对任何这些东西都没有可访问的引用,并且链接的唯一一件事是while循环的作用域,它正在等待某些诺言兑现,那么引擎会舍弃它吗?还是让while循环作用域运行,等待Promises?
如果while循环仍然存在(我猜是这样),我应该如何清理呢?
最佳答案
有趣的用例啊!这似乎是AbortController的一个很好的用例:
function nextEvent(target, type, abortSignal) {
return new Promise(resolve => {
target.addEventListener(type, resolve, { once: true });
abortSignal.addEventListener("abort", () =>
target.removeEventListener(type, resolve)
);
});
}
const abortController = new AbortController();
const event = await Promise.race([
nextEvent(someButton, "click", abortController.signal),
nextEvent(someButton, "keydown", abortController.signal)
]);
// Clean up all remaining event handlers
abortController.abort();
// Continue as normal