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

JavaScript重构:消除依赖相似元素列表对象的代码重复

引言

假设有10个入参均为(uid, data)的异步函数:

const a = async (uid, data) => { ... };
const b = async (uid, data) => { ... };
const c = async (uid, data) => { ... };
const d = async (uid, data) => { ... };
const e = async (uid, data) => { ... };
const f = async (uid, data) => { ... };
const g = async (uid, data) => { ... };
const h = async (uid, data) => { ... };
const i = async (uid, data) => { ... };
const j = async (uid, data) => { ... };

以及4个业务键:"key1", "key2", "key3", "key4"
当前已定义结构固定的常量映射对象:

const OBJECT = { // 固定结构常量
  key1: [a, b, c, d, e, f, h, i, j],
  key2: [a, b, c, d, f, i, j],
  key3: [a, b, c, d, e, f, g, h, i, j],
  key4: [a, b, c, d, e, f, h, i, j],
}

现有代码的使用方式如下:

const uid = uuid.v4();

const dynamicData = { // 可能包含任意个key1-key4范围内的业务键
  key1,
  key2,
};

let selectedMethods = [];

Object.keys(dynamicData).forEach((key) => {
  if (key in OBJECT) {
    selectedMethods.push(...OBJECT[key]);
  }
});

// 借助lodash做数组去重
selectedMethods = _.uniq(selectedMethods);

const promises = selectedMethods.map(
  (method) => method(uid, dynamicData)
);

await Promise.all(promises);

问题描述

现有代码存在两个核心问题:

  • 常量对象初始化存在大量重复的函数引用,维护成本高,容易出现漏改、错改
  • 执行逻辑是散落在业务中的过程式面条代码,所有方法入参模式完全一致但没有做逻辑收敛,复用性差
    需要给出针对性的优化方案,提升代码可维护性。

优化方案

一、常量定义层优化:消除重复,收敛维护入口

原始实现最大的痛点是同一个函数引用在多个数组中重复书写,调整公共方法时需要同步修改多处配置,极易出现不一致问题。优化核心思路是抽离公共部分,只维护差异配置:

  • 统一收敛所有业务方法的定义入口,后续新增、删除、替换方法仅需修改一处
  • 抽离所有业务键共有的基础方法集,不需要在每个key的配置中重复书写
  • 每个业务键仅配置自身和基础集有差异的增量方法
  • 最终常量映射由基础集+增量方法自动生成,生成后冻结保证不可变性,避免运行时意外篡改

优化后的常量定义代码:

// 1. 所有方法的统一维护入口
const METHOD_MAP = Object.freeze({ a, b, c, d, e, f, g, h, i, j });

// 2. 所有业务键共有的基础方法集
const BASE_METHODS = Object.freeze([a, b, c, d, f, i, j]);

// 3. 每个业务键的专属增量方法配置,仅写和基础集的差异部分
const KEY_METHOD_CONFIG = Object.freeze({
  key1: [e, h],
  key2: [],
  key3: [e, g, h],
  key4: [e, h],
});

// 4. 自动生成最终常量映射,生成后冻结
const OBJECT = Object.freeze(
  Object.fromEntries(
    Object.entries(KEY_METHOD_CONFIG).map(([key, extraMethods]) => [
      key,
      Object.freeze([...BASE_METHODS, ...extraMethods])
    ])
  )
);

该实现消除了90%以上的重复配置,后续调整公共方法仅需修改BASE_METHODS,调整单个key的方法仅需修改对应增量数组,维护成本大幅降低。

二、执行逻辑层重构:封装复用,收敛流程

原始执行逻辑是过程式代码,每次使用都需要重复写遍历、去重、执行的逻辑,且依赖外部lodash库做去重。优化核心思路是把整个执行流程封装为独立的可复用函数,业务侧仅需传入参数获取结果,不需要关心内部实现细节:

  • 用原生Set结构实现自动去重,移除对lodash的依赖
  • 把uid生成、方法匹配、批量执行、异常边界判断的逻辑全部收敛到函数内部
  • 保持原有执行逻辑不变,不会引入业务兼容问题

优化后的执行逻辑代码:

/**
 * 按动态配置匹配并执行对应方法
 * @param {Record<string, any>} dynamicData 动态业务配置,key为业务键
 * @returns {Promise<any[]>} 所有匹配方法的执行结果集合
 */
async function runMatchedMethods(dynamicData) {
  const uid = uuid.v4();
  // 用Set自动去重,避免重复执行同一个方法
  const matchedMethods = new Set();

  for (const key of Object.keys(dynamicData)) {
    const methodList = OBJECT[key];
    // 不存在的key直接跳过,避免异常
    if (!methodList) continue;
    methodList.forEach(method => matchedMethods.add(method));
  }

  // 批量执行所有方法,统一等待结果
  return Promise.all(
    Array.from(matchedMethods).map(method => method(uid, dynamicData))
  );
}

业务侧调用时仅需一行代码即可完成原有逻辑:

const execResults = await runMatchedMethods(dynamicData);

可选扩展方向

如果后续业务复杂度提升,可以在现有分层结构上快速扩展,不需要重构核心逻辑:

  • 如果需要支持「排除特定方法」的配置,仅需把KEY_METHOD_CONFIG的配置项改为{ include: [], exclude: [] }结构,生成方法列表时过滤掉exclude中的方法即可
  • 如果需要方法按顺序执行,仅需把Promise.all替换为for...of循环依次调用即可
  • 如果需要统一加错误捕获、超时、日志逻辑,仅需在方法执行的map回调中统一添加即可,不需要修改每个业务方法

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 20:57:28