同步/异步代码复用方案咨询:如何减少重复逻辑维护工作量?
问题描述
我写了两个几乎完全相同的同步与异步函数,示例代码如下:
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
相关产品推荐
相关产品推荐

