Angular中setInterval调用EventEmitter.emit报TypeError问题求助
解决Angular中setInterval里无法调用EventEmitter的问题
这个问题我之前踩过坑!核心原因就是你用普通function作为setInterval的回调时,this的指向已经不再是你的GameComponent实例了——在严格模式下它会变成undefined,所以自然找不到raiseEvent属性,才会抛出Cannot read property 'emit' of undefined的错误。
下面给你三种靠谱的解决方法,按推荐程度排序:
1. 使用箭头函数(最推荐的TypeScript/Angular写法)
箭头函数不会创建自己的this上下文,它会直接沿用定义时所在作用域的this,也就是你的组件实例。修改后的代码如下:
StartGame() { setInterval(() => { this.raiseEvent.emit({currentEvent : this.currentEventCount++}); }, 1000); }
这样写不仅简洁,还完美避开了作用域问题,是Angular项目里处理这类回调的标准做法。
2. 提前保存组件的this到变量
如果你更习惯用普通函数,也可以在setInterval外面把组件的this存到一个变量里,比如self或者component,然后在回调里用这个变量访问组件的属性和方法:
StartGame() { const self = this; // 把组件实例的this存起来 setInterval(function () { self.raiseEvent.emit({currentEvent : self.currentEventCount++}); }, 1000); }
这种方法兼容性很好,在旧版JavaScript里也常用,但不如箭头函数简洁。
3. 用bind()绑定this
你可以通过bind()方法把回调函数的this强制绑定到组件实例上,这样回调里的this就会一直指向组件:
StartGame() { setInterval(function () { this.raiseEvent.emit({currentEvent : this.currentEventCount++}); }.bind(this), 1000); // 绑定组件的this到回调函数 }
这种方法也能解决问题,但代码可读性不如箭头函数,一般不推荐在Angular里用。
额外提醒:记得清理定时器!
最后给你加个最佳实践:Angular组件销毁时一定要清除定时器,不然会导致内存泄漏。你可以把定时器的ID存起来,在ngOnDestroy钩子中清理:
import {Component, EventEmitter, OnInit, OnDestroy, Output} from '@angular/core'; @Component({ selector: 'app-game', templateUrl: './game.component.html', styleUrls: ['./game.component.css'] }) export class GameComponent implements OnInit, OnDestroy { @Output() raiseEvent: EventEmitter<{currentEvent: number}> = new EventEmitter<{currentEvent: number}>(); currentEventCount = 1; private intervalId: number | undefined; // 存储定时器ID constructor() { } ngOnInit() { } StartGame() { this.intervalId = setInterval(() => { this.raiseEvent.emit({currentEvent : this.currentEventCount++}); }, 1000); } ngOnDestroy() { if (this.intervalId) { clearInterval(this.intervalId); // 组件销毁时清除定时器 } } }
内容的提问来源于stack exchange,提问作者darkking
相关产品推荐
相关产品推荐

