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

同步/异步代码复用方案咨询:如何减少重复逻辑维护工作量?

问题描述

我写了两个几乎完全相同的同步与异步函数,示例代码如下:

const regExpSync = (str, pat, fn) => {
  let loc = 0;
  let res;
  while((res = pat.exec(str.substring(loc)))){
    const rtn = fn(res);
    if(rtn) return rtn;
    loc += res.length + res.index;
  }
};

const regExpAsync = async (str, pat, fn) => {
  let loc = 0;
  let res;
  while((res = pat.exec(str.substring(loc)))){
    const rtn = await fn(res);
    if(rtn) return rtn;
    loc += res.length + res.index;
  }
};

const testPat = new RegExp('[a-z]+');
const testStr = '------aa-----abc--------zz--------dd----------';

console.log('-');
regExpSync(testStr, testPat, ([str]) => { console.log(str); return false; });
console.log('-');
await regExpAsync(testStr, testPat, async ([str]) => { console.log(str); return false; });
console.log('-');

实际业务逻辑比正则示例复杂得多,但核心问题是:每次逻辑变更都要同时修改同步和异步两个版本的代码。我尝试过用判断AsyncFunction的方式整合,但复用率还是不够,体验不佳:

const regExp = (str, pat, fn) => {
  if(fn.constructor.name == 'AsyncFunction') return (async () => {

    let loc = 0;
    let res;
    while((res = pat.exec(str.substring(loc)))){
      const rtn = await fn(res);
      if(rtn) return rtn;
      loc += res.length + res.index;
    }

  })();
  else {

    let loc = 0;
    let res;
    while((res = pat.exec(str.substring(loc)))){
      const rtn = fn(res);
      if(rtn) return rtn;
      loc += res.length + res.index;
    }
    
  }
};

请问有没有更优的方案提升代码复用率,减少重复修改的工作量?


解决方案

方法1:提取核心逻辑,用包装函数处理同步/异步差异

把重复的循环逻辑抽成通用核心函数,同步和异步版本只负责适配回调的执行方式(是否加await):

// 核心业务逻辑:只处理循环流程,回调执行交给外部传入的处理函数
const coreLogic = (str, pat, handleFn) => {
  let loc = 0;
  let res;
  while((res = pat.exec(str.substring(loc)))){
    const rtn = handleFn(res);
    if(rtn) return rtn;
    loc += res.length + res.index;
  }
};

// 同步版本:直接执行回调
const regExpSync = (str, pat, fn) => {
  return coreLogic(str, pat, (res) => fn(res));
};

// 异步版本:异步执行回调并await结果
const regExpAsync = async (str, pat, fn) => {
  return coreLogic(str, pat, async (res) => await fn(res));
};

后续业务逻辑变更只需要修改coreLogic,同步/异步版本无需改动。

方法2:统一返回Promise,兼容同步/异步回调

如果业务流程允许异步优先,可以只维护一个异步版本——同步回调返回的普通值可以被await直接处理:

const regExp = async (str, pat, fn) => {
  let loc = 0;
  let res;
  while((res = pat.exec(str.substring(loc)))){
    // 不管fn是同步还是异步,统一用await处理结果
    const rtn = await fn(res);
    if(rtn) return rtn;
    loc += res.length + res.index;
  }
};

// 使用方式:同步回调也需要用await或.then处理
await regExp(testStr, testPat, ([str]) => { console.log(str); return false; });
await regExp(testStr, testPat, async ([str]) => { console.log(str); return false; });

这种方式彻底消除重复代码,代价是原本的同步调用变为异步(返回Promise),适合已经采用异步流程的业务场景。

方法3:用高阶函数生成同步/异步版本

通过工厂函数根据参数生成对应的处理函数,核心逻辑只写一次:

const createRegExpHandler = (isAsync) => {
  return isAsync 
    ? async (str, pat, fn) => {
        let loc = 0;
        let res;
        while((res = pat.exec(str.substring(loc)))){
          const rtn = await fn(res);
          if(rtn) return rtn;
          loc += res.length + res.index;
        }
      }
    : (str, pat, fn) => {
        let loc = 0;
        let res;
        while((res = pat.exec(str.substring(loc)))){
          const rtn = fn(res);
          if(rtn) return rtn;
          loc += res.length + res.index;
        }
      };
};

// 生成同步和异步版本
const regExpSync = createRegExpHandler(false);
const regExpAsync = createRegExpHandler(true);

后续修改业务逻辑只需调整工厂函数内部的核心代码,无需维护两个独立函数。

方法4:用工具函数统一处理回调执行

编写工具函数自动识别回调是同步还是异步,再在核心逻辑中调用:

// 工具函数:统一处理同步/异步回调的执行
const executeFn = async (fn, ...args) => {
  const result = fn(...args);
  return result instanceof Promise ? await result : result;
};

// 统一版本:基于异步逻辑实现,自动适配回调类型
const regExp = async (str, pat, fn) => {
  let loc = 0;
  let res;
  while((res = pat.exec(str.substring(loc)))){
    const rtn = await executeFn(fn, res);
    if(rtn) return rtn;
    loc += res.length + res.index;
  }
};

该方案可读性更强,同样只需维护一份核心逻辑。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 22:17:23