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

TypeScript处理100MB大JSON文件的排序报错及性能优化问题

问题解决方案

一、TypeScript类型报错修复

报错原因

AccountSearchCriteria接口中sortField被定义为string类型,TypeScript无法保证该字符串一定是Account接口的合法属性名,因此用字符串索引Account类型对象时触发了类型校验错误。

修复步骤

  1. 修改AccountSearchCriteria接口的sortField类型,限定取值只能为Account的合法属性名
// account.ts 修改后内容
export interface Account {
    firstName: string;
    lastName: string;
    country: string;
    email: string;
    dob: string;
    mfa?: MFA;
    amt: number;
    createdDate: string;
    referredBy?: string;
}
export enum MFA {
    SMS = 'SMS',
    TOTP = 'TOTP'
}

export interface AccountSearchCriteria {
    country?: string;
    mfa?: string;
    name?: string;
    // 将sortField类型从string改为Account的属性联合类型
    sortField?: keyof Account;
}
  1. 优化排序逻辑,区分不同字段类型的排序规则,补全相等场景的返回值(原写法相等时返回1会导致排序不稳定)
// main.ts 排序部分修改后内容
if (accountSearchCriteria.sortField) {
  const sortKey = accountSearchCriteria.sortField;
  accounts.sort((a, b) => {
    const valA = a[sortKey];
    const valB = b[sortKey];
    // 数字类型直接相减得到正确排序结果
    if (typeof valA === 'number' && typeof valB === 'number') {
      return valA - valB;
    }
    // 字符串/其他类型用localeCompare处理排序
    return String(valA).localeCompare(String(valB));
  });
}

二、100MB大文件性能优化方案

当前代码的性能瓶颈主要有两点:一是一次性加载全量JSON到内存,全量解析成本高;二是多次遍历数组执行过滤,存在大量冗余计算。可按以下优先级优化:

1. 基础优化(无需引入第三方依赖)

  • 合并多次过滤为单次遍历:原代码三次filter会遍历数组三次,合并为一次遍历即可完成所有条件校验
  • 预先计算过滤条件的静态值:提前把搜索条件的toLowerCase结果计算好,避免在遍历回调中重复执行
// 优化后的过滤逻辑
const nameLower = accountSearchCriteria.name?.toLowerCase();
const countryLower = accountSearchCriteria.country?.toLowerCase();
const targetMfa = accountSearchCriteria.mfa;

// 单次遍历完成所有过滤
accounts = accounts.filter(account => {
  if (nameLower) {
    const firstNameMatch = account.firstName.toLowerCase() === nameLower;
    const lastNameMatch = account.lastName.toLowerCase() === nameLower;
    if (!firstNameMatch && !lastNameMatch) return false;
  }
  if (countryLower && account.country.toLowerCase() !== countryLower) return false;
  if (targetMfa && account.mfa !== targetMfa) return false;
  return true;
});

2. 流式解析优化(大文件最优方案)

不用一次性读取全量文件,使用流式JSON解析库逐对象解析,只保留符合条件的账户对象,大幅降低内存占用,提升解析速度,示例如下:

import { createReadStream } from 'fs';
import { parser } from '@streamparser/json';

async function filterAccounts(jsonPath: string, criteria: AccountSearchCriteria) {
  const result: Account[] = [];
  const nameLower = criteria.name?.toLowerCase();
  const countryLower = criteria.country?.toLowerCase();
  const targetMfa = criteria.mfa;

  return new Promise<Account[]>((resolve, reject) => {
    createReadStream(jsonPath, 'utf-8')
      // 配置解析数组内的每个账户对象
      .pipe(parser({ paths: ['$.*'] }))
      .on('data', ({ value }) => {
        const account = value as Account;
        let match = true;
        if (nameLower) {
          const firstNameMatch = account.firstName.toLowerCase() === nameLower;
          const lastNameMatch = account.lastName.toLowerCase() === nameLower;
          match = firstNameMatch || lastNameMatch;
        }
        if (match && countryLower) match = account.country.toLowerCase() === countryLower;
        if (match && targetMfa) match = account.mfa === targetMfa;
        if (match) result.push(account);
      })
      .on('end', () => {
        // 过滤完成后再执行排序
        if (criteria.sortField) {
          const sortKey = criteria.sortField;
          result.sort((a, b) => {
            const valA = a[sortKey];
            const valB = b[sortKey];
            if (typeof valA === 'number' && typeof valB === 'number') return valA - valB;
            return String(valA).localeCompare(String(valB));
          });
        }
        resolve(result);
      })
      .on('error', reject);
  });
}

该方案可将100MB文件的内存占用从数百MB降低到几十MB,解析耗时可减少50%以上。

3. 可选优化

如果需要反复查询同一数据源,可将解析过滤后的结果做本地缓存,避免每次请求都重新解析大文件。

内容的提问来源于stack exchange,提问作者B. Abdo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 01:45:01