You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js路由点击后加载延迟、页面崩溃问题及代码排查求助

问题原因

你提供的代码核心问题是没有在组件卸载时清除路由事件监听器,属于典型的事件绑定类内存泄漏:

  • 这段代码大概率写在组件的挂载生命周期(比如React的componentDidMount或者useEffect的回调里),每次组件被挂载时,都会给Router.events新增3个事件监听函数
  • 这些监听函数是匿名箭头函数,内部持有当前组件实例的引用,只要监听不解除,组件实例就无法被垃圾回收(GC),内存占用会随着路由跳转次数持续上涨
  • 每次路由事件触发时,所有历史注册的监听函数都会同时执行,会批量触发N次无意义的setState调用,导致页面卡顿、响应延迟,调用次数过多就会直接崩溃
  • 本地和预发环境没问题是因为测试时跳转次数少,泄漏量没达到卡顿阈值,线上用户长时间使用、多次跳转就会暴露问题
修复方案

如果是类组件,在componentWillUnmount生命周期里移除对应的监听:

componentWillUnmount() {
  Router.events.off('routeChangeStart', this.handleRouteStart)
  Router.events.off('routeChangeComplete', this.handleRouteComplete)
  Router.events.off('routeChangeError', this.handleRouteError)
}
// 挂载时需要把匿名函数提取成实例方法,不然off的时候找不到对应的函数引用
componentDidMount() {
  const isBrowser = typeof window !== 'undefined'
  if (isBrowser) {
    this.setState({ isLoading: false })
  }
  this.handleRouteStart = () => this.setState({ isLoading: true })
  this.handleRouteComplete = () => this.setState({ isLoading: false })
  this.handleRouteError = () => this.setState({ isLoading: false })

  Router.events.on('routeChangeStart', this.handleRouteStart)
  Router.events.on('routeChangeComplete', this.handleRouteComplete)
  Router.events.on('routeChangeError', this.handleRouteError)
}

如果是函数组件,用useEffect的清理函数处理:

useEffect(() => {
  const isBrowser = typeof window !== 'undefined'
  if (isBrowser) {
    setIsLoading(false)
  }
  const handleRouteStart = () => setIsLoading(true)
  const handleRouteComplete = () => setIsLoading(false)
  const handleRouteError = () => setIsLoading(false)

  Router.events.on('routeChangeStart', handleRouteStart)
  Router.events.on('routeChangeComplete', handleRouteComplete)
  Router.events.on('routeChangeError', handleRouteError)

  // 清理函数,组件卸载/依赖更新时执行
  return () => {
    Router.events.off('routeChangeStart', handleRouteStart)
    Router.events.off('routeChangeComplete', handleRouteComplete)
    Router.events.off('routeChangeError', handleRouteError)
  }
}, [])
调试建议
  • 打开Chrome开发者工具的内存(Memory)面板,先拍一个堆快照,然后多次跳转路由后再拍一个堆快照,对比两个快照里的组件实例、事件监听数量,就能直接看到泄漏的对象
  • 用开发者工具的性能(Performance)面板,录制多次路由跳转的执行过程,查看主线程执行耗时,就能看到大量重复的setState调用占比
  • 可以在Router事件监听的回调里加console日志,多次跳转后触发路由时看控制台打印的日志数量,就能直观看到监听器重复注册的问题
  • 检查是否还有其他全局事件(比如window的resize、scroll事件)没有做解绑处理,这类全局绑定的事件是前端内存泄漏的高发点

内容的提问来源于stack exchange,提问作者MomasVII

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 07:42:00