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

本地运行时致笔记本死机的无限循环问题排查

解决Next.js开发服务器运行后笔记本死机问题(Supabase分级读物项目)

我正在开发一个面向语言学习者的分级读物筛选页面,核心功能是通过下拉菜单选择语言,从Supabase加载对应语言的分级读物,后续计划添加级别、体裁筛选和亚马逊购买链接。但目前执行npm run dev启动开发服务器后,运行1-2分钟笔记本就会死机,必须强制重启。我已经反复优化前端代码,但问题依旧,前端代码如下:

'use client';

import { useEffect, useState } from 'react';

type Book = {
  id: string;
  title: string;
  author?: string;
};

const languageOptions = [
  { value: 'spanish', label: 'Spanish' },
  { value: 'french', label: 'French' },
  { value: 'german', label: 'German' },
] as const;

type LanguageValue = (typeof languageOptions)[number]['value'];

export default function HomePage() {
  const [books, setBooks] = useState<Book[]>([]);
  const [table, setTable] = useState<LanguageValue>('spanish');
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState('');

  useEffect(() => {
    let active = true;

    async function loadBooks() {
      try {
        setIsLoading(true);
        setError('');

        const response = await fetch(
          `/api/books?table=${encodeURIComponent(table)}`
        );

        if (!response.ok) {
          throw new Error('Failed to load books');
        }

        const result = await response.json();

        if (!active) return;

        setBooks(Array.isArray(result?.data) ? result.data : []);
      } catch (err) {
        if (!active) return;

        setBooks([]);
        setError(
          err instanceof Error ? err.message : 'Something went wrong'
        );
      } finally {
        if (active) {
          setIsLoading(false);
        }
      }
    }

    loadBooks();

    return () => {
      active = false;
    };
  }, [table]);

  return (
    <main>
      <h1>
        Books in{' '}
        {languageOptions.find((l) => l.value === table)?.label}
      </h1>

      <select
        value={table}
        onChange={(e) =>
          setTable(e.target.value as LanguageValue)
        }
      >
        {languageOptions.map((item) => (
          <option key={item.value} value={item.value}>
            {item.label}
          </option>
        ))}
      </select>

      {isLoading && <p>Loading...</p>}
      {error && <p>{error}</p>}

      <ul>
        {books.map((book) => (
          <li key={book.id}>
            {book.title}
            {book.author && ` — ${book.author}`}
          </li>
        ))}
      </ul>
    </main>
  );
}

排查方向与修复方案

1. 重点检查API路由实现

前端代码逻辑本身没有明显问题,死机大概率出在/api/books后端接口:

  • 避免无限查询:确认接口是否存在无限循环调用Supabase的情况,比如错误的条件判断导致重复查询。
  • 添加数据限流:如果Supabase表中数据量极大,一次返回全量数据会直接撑爆前端内存。给查询加limit限制:
// 在/api/books中添加限流逻辑
const { data } = await supabase
  .from(req.query.table)
  .select('*')
  .limit(50); // 一次只返回50条数据
  • 参数合法性校验:先判断table参数是否在允许的列表(spanish/french/german)中,非法参数直接返回400错误,避免无效查询。

2. 监控前端资源占用

  • 打开浏览器DevTools的Network标签,观察/api/books请求是否被频繁触发(比如每秒多次),如果是,检查是否有意外的状态更新导致useEffect重复执行。
  • 用Performance标签录制性能日志,定位CPU和内存占用的峰值来源。
  • 用Memory标签检测内存是否持续增长,排查内存泄漏。

3. 优化前端渲染压力

即使接口返回大量数据,渲染成百上千个<li>元素也会导致DOM节点过载,添加分页功能:

// 在HomePage组件中添加分页状态
const [currentPage, setCurrentPage] = useState(1);
const itemsPerPage = 20;

// 计算当前页要显示的书籍
const displayedBooks = books.slice(
  (currentPage - 1) * itemsPerPage,
  currentPage * itemsPerPage
);

// 渲染displayedBooks替代原books数组
<ul>
  {displayedBooks.map((book) => (
    <li key={book.id}>
      {book.title}
      {book.author && ` — ${book.author}`}
    </li>
  ))}
</ul>

// 添加分页控制按钮
<div style={{ marginTop: '1rem' }}>
  <button 
    onClick={() => setCurrentPage(prev => Math.max(1, prev - 1))}
    disabled={currentPage === 1}
  >
    上一页
  </button>
  <button 
    onClick={() => setCurrentPage(prev => prev + 1)}
    disabled={displayedBooks.length < itemsPerPage}
  >
    下一页
  </button>
</div>

4. 排查热重载问题

临时禁用Next.js热重载测试,如果死机消失,说明是热重载相关的资源泄漏:

  • 在next.config.js中添加配置:
module.exports = {
  webpackDevMiddleware: config => {
    config.watchOptions = {
      poll: false,
      ignored: /node_modules/,
    };
    return config;
  },
};
  • 或者启动时添加参数:npm run dev -- --no-hmr
  • 若问题解决,尝试升级Next.js到最新稳定版本。

5. 规范Supabase客户端初始化

确保在API路由中只创建一次Supabase客户端实例,避免重复创建导致资源占用:

// /api/books的正确初始化方式
import { createClient } from '@supabase/supabase-js';

export default async function handler(req, res) {
  // 只在请求处理时创建一次客户端
  const supabase = createClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL,
    process.env.SUPABASE_SERVICE_ROLE_KEY
  );
  
  // 后续查询逻辑...
}

内容的提问来源于stack exchange,提问作者E1888-Repair

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.04 07:04:50