内置的events https://devdocs.io/node~8_lts/events模块输入node.js https://nodejs.org/(如果您使用以下命令进行编译,则该版本将捆绑到您的前端应用程序中webpack https://webpack.js.org/ or browserify http://browserify.org/)对您的代码做出一些假设。某个时候,某个地方,有人决定如果你有X
注册的听众数量,那么surely你有内存泄漏。有时它是正确的,并正确地提醒你去寻找泄漏点。
我多次收到此警告,但通常只有两个特定原因,这两个原因都有简单的解决方案:
问题1:绑定事件监听器函数不匹配
您的组件可能如下所示,其中您使用组件方法作为事件侦听器,并且绑定它当你注册时.
import events from '../lib/events' // some singleton event emitter
class MyComponent extends React.Component {
componentDidMount() {
events.addEventListener('some-event', this.myMethod.bind(this))
}
componentWillUnmount() {
events.removeEventListener('some-event', this.myMethod.bind(this))
}
myMethod() {
// does something
}
render() {
// gotta have this too
}
}
这里的问题是function.bind https://devdocs.io/javascript/global_objects/function/bind创建一个新功能每次,您尝试删除的功能都与您添加的功能不同。因此,添加的函数不断增加(不好的双关语),并且实际上确实存在内存泄漏。
解决方案 1:尽早绑定您的方法
尽早绑定你的方法,通常在constructor()
。然后每次都可以参考绑定的版本,确保移除的功能与添加的功能相同。
import events from '../lib/events' // some singleton event emitter
class MyComponent extends React.Component {
constructor() {
// bind your method early so the function removed
// is the same as the function added
this.myMethod = this.myMethod.bind(this)
}
componentDidMount() {
events.addEventListener('some-event', this.myMethod)
}
componentWillUnmount() {
events.removeEventListener('some-event', this.myMethod)
}
myMethod() {
// does something
}
render() {
// gotta have this too
}
}
问题 2:大量的事件监听器
有时,您确实做了功课,并仔细检查了是否已根据需要尽早绑定了听众,然后将它们全部删除在适当的位置。然后你仔细观察,发现你正在做这样的事情:
import MyComponent from './MyComponent' // same component above
class Parent extends React.Component {
render() {
return (
<div>
{ this.props.largeArray.map(MyComponent) }
</div>
)
}
}
Suppose this.props.largeArray
有 50 个、100 个或可能 250 个元素。这意味着(按照设计!)您正在渲染 250 个实例MyComponent
,每个都注册另一个唯一的事件侦听器。
不要害怕!这是完全有效的代码,并且没有内存泄漏。但它确实突破了某人在某个时间、某个地方任意决定帮助保护你的最大听众限制。
解决方案 2:切换到使用eventemitter3 https://www.npmjs.com/package/eventemitter3
如果您确定已经完成了作业,并仔细检查了所有内容,并且(按设计!)注册了大量事件侦听器,那么最简单的解决方案是切换到使用eventemitter3 https://www.npmjs.com/package/eventemitter3,这是节点的直接替代品events
模块,除了速度更快,并且与浏览器兼容,并且不会为您设置最大侦听器限制。
使用方法和内置的一样events
module:
const EventEmitter = require('eventemitter3')
const emitter = new EventEmitter()