如何提取异步与同步相似方法的公共逻辑并正确处理Promise?
复用同步/异步迭代逻辑的解决方案
嘿,这个问题我之前也遇到过——同步和异步逻辑几乎一模一样,但因为循环里的回调处理方式不同,总觉得重复代码很别扭对吧?这里有几个实用的方案帮你复用核心逻辑,同时处理异步场景的Promise等待:
方案1:抽象回调处理逻辑,复用核心循环
最直接的思路是把循环迭代的核心逻辑抽成独立函数,把“如何处理回调调用”作为参数传入——同步场景直接执行回调,异步场景收集Promise。这样核心的循环逻辑完全复用,只把差异点抽离:
// 核心迭代逻辑:只负责遍历IP,不关心回调是同步还是异步 function iterateCore(handleCallback) { let firstIteration = true; let lastIp; // 这里保留你原来的循环判断逻辑 while (lastIp = (firstIteration && /* 你的初始IP获取逻辑 */) || /* 下一个IP的获取逻辑 */) { firstIteration = false; // 把当前IP交给传入的处理函数处理 handleCallback(lastIp); } } // 同步方法:直接执行回调 iterate(callback) { iterateCore((ip) => { callback(ip); }); } // 异步方法:收集所有Promise并等待完成 async iterateAsync(callback) { const promises = []; iterateCore((ip) => { // 收集回调返回的Promise promises.push(callback(ip)); }); // 等待所有异步操作完成 await Promise.all(promises); }
这个方案的好处是核心逻辑完全没有重复,同步和异步的差异被压缩到最小,代码可读性也很高。
方案2:统一用Promise包装(兼容混合场景)
如果你的回调本身可能既支持同步又支持异步(有时候返回Promise,有时候不返回),或者你想让两个方法的接口更统一,可以统一用Promise.resolve()包装回调调用,这样不管同步还是异步都能当作Promise处理:
// 复用的核心迭代逻辑,返回Promise数组 function getIterationTasks(callback) { const tasks = []; let firstIteration = true; let lastIp; while (lastIp = (firstIteration && /* 初始IP逻辑 */) || /* 下一个IP逻辑 */) { firstIteration = false; // 统一包装成Promise,兼容同步/异步回调 tasks.push(Promise.resolve(callback(lastIp))); } return tasks; } // 同步方法:直接执行所有任务(不等待,保持同步行为) iterate(callback) { getIterationTasks(callback).forEach(task => task.then(() => {})); } // 异步方法:等待所有任务完成 async iterateAsync(callback) { await Promise.all(getIterationTasks(callback)); }
这个方案适合回调类型不确定的场景,同时依然复用了核心的循环逻辑。
额外小提示:如果需要串行执行异步回调
如果你的异步场景需要串行执行(等前一个回调完成再执行下一个),而不是并行,那可以修改异步方法的逻辑,在循环里直接await:
async iterateAsyncSerial(callback) { let firstIteration = true; let lastIp; while (lastIp = (firstIteration && /* 初始IP逻辑 */) || /* 下一个IP逻辑 */) { firstIteration = false; // 串行等待每个回调完成 await callback(lastIp); } }
这种情况下核心循环还是可以复用,只需要把handleCallback改成异步的:
async iterateCoreAsync(handleCallback) { let firstIteration = true; let lastIp; while (lastIp = (firstIteration && /* 初始IP逻辑 */) || /* 下一个IP逻辑 */) { firstIteration = false; await handleCallback(lastIp); } } async iterateAsyncSerial(callback) { await iterateCoreAsync((ip) => callback(ip)); }
这样不管并行还是串行,核心逻辑都能复用。
内容的提问来源于stack exchange,提问作者Kamil Janowski
相关产品推荐
相关产品推荐

