Angular中使用lodash.debounce包裹函数后失效,如何解决?
问题描述
我编写了一个响应window的click、mousemove、keydown事件的函数,该函数会调用AuthService的sessionExtention接口。不使用防抖时功能正常,但频繁触发事件会导致服务器崩溃。尝试用lodash.debounce包裹该函数后,函数却停止工作了,请问问题出在哪里?如何修复?
原代码片段
resethUserState() { this.authService.sessionExtention().subscribe(); console.log('reset'); } @HostListener('window:click') @HostListener('window:mousemove') @HostListener('window:keydown') function() { debounce(this.resethUserState, 1000); }
完整组件代码
import { Component, HostListener, OnInit } from '@angular/core'; import { AuthService } from '../../auth.service'; import { Router } from '@angular/router'; import Paths from '../../paths'; import { PushNotificationService } from 'src/app/push-notification.service'; import debounce from 'lodash.debounce'; @Component({ selector: 'app-lobby', templateUrl: './lobby.component.html', styleUrls: ['./lobby.component.scss'], }) export class LobbyComponent implements OnInit { constructor( private router: Router, private authService: AuthService, private pushNotificationService: PushNotificationService ) { } ngOnInit(): void {} logoutUser() { this.authService.logout(); this.pushNotificationService.createNotification('Logged out!'); this.router.navigate([`/${Paths.Login}`]); return false; } resetUserState() { this.authService.sessionExtention().subscribe(); console.log('reset'); } @HostListener('window:click') @HostListener('window:mousemove') @HostListener('window:keydown') function() { debounce(this.resetUserState, 1000); } }
问题原因
- 防抖函数未执行:你现在只是在事件处理里创建了防抖函数,但没有调用它。
debounce(...)返回的是一个新的防抖包装函数,必须执行这个返回值才会触发逻辑。 - this指向丢失:直接把
this.resetUserState传给debounce时,函数内部的this会脱离组件实例,导致调用this.authService时出错。 - 重复创建防抖函数:每次事件触发都会生成全新的防抖函数,这些函数互相独立,根本起不到“防抖”的作用——防抖需要复用同一个函数实例来追踪时间间隔。
修复方案
推荐提前初始化防抖函数实例的方式,这是最规范的做法:
import { Component, HostListener, OnInit, OnDestroy } from '@angular/core'; import { AuthService } from '../../auth.service'; import { Router } from '@angular/router'; import Paths from '../../paths'; import { PushNotificationService } from 'src/app/push-notification.service'; import debounce from 'lodash.debounce'; @Component({ selector: 'app-lobby', templateUrl: './lobby.component.html', styleUrls: ['./lobby.component.scss'], }) export class LobbyComponent implements OnInit, OnDestroy { // 提前创建防抖函数实例,用箭头函数绑定当前组件的this private debouncedReset = debounce(() => this.resetUserState(), 1000); constructor( private router: Router, private authService: AuthService, private pushNotificationService: PushNotificationService ) {} ngOnInit(): void {} // 组件销毁时取消防抖定时器,避免内存泄漏 ngOnDestroy(): void { this.debouncedReset.cancel(); } logoutUser() { this.authService.logout(); this.pushNotificationService.createNotification('Logged out!'); this.router.navigate([`/${Paths.Login}`]); return false; } resetUserState() { this.authService.sessionExtention().subscribe(); console.log('reset'); } @HostListener('window:click') @HostListener('window:mousemove') @HostListener('window:keydown') onUserActivity() { // 调用提前创建好的防抖函数 this.debouncedReset(); } }
临时测试方案(不推荐长期使用)
如果只是临时验证,可以直接在事件处理中调用防抖后的函数,但这种方式每次事件都会创建新的防抖函数,无法复用状态:
@HostListener('window:click') @HostListener('window:mousemove') @HostListener('window:keydown') onUserActivity() { debounce(() => this.resetUserState(), 1000)(); }
内容的提问来源于stack exchange,提问作者Vladimir
相关产品推荐
相关产品推荐

