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('-');

我有几乎相同的异步和同步代码.

这只是一个例子,实际上它是更复杂的逻辑,与正则表达式无关.

无论如何,两者都作为回调函数fn工作.

每当这一逻辑发生变化时,我都会修改这两个文件.

有什么 idea 可以把修改降到最低吗?

我试了一下,但不是很方便.

在这里,我们可以提高代码的重用性吗?

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;
    }
    
  }
};

推荐答案

您可以使用生成器函数来抽象出循环:

function* regExp(str, pat) {
  let loc = 0;
  let res;
  while((res = pat.exec(str.substring(loc)))){
    yield res;
    loc += res.length + res.index;
  }
}
function regExpSync(str, pat, fn) {
  for (const res of regExp(str, pat)) {
    const rtn = fn(res);
    if(rtn) return rtn;
  }
}
async function regExpAsync(str, pat, fn) {
  for (const res of regExp(str, pat)) {
    const rtn = await fn(res);
    if (rtn) return rtn;
  }
}

请注意,使用regExp返回的迭代器,您甚至可以使用iterator helper methods进一步简化:

 const regExpSync = (str, pat, fn) => regExp(str, pat).some(fn);
 // or strictly
 const regExpSync = (str, pat, fn) => regExp(str, pat).map(fn).find(Boolean);

 const regExpAsync = (str, pat, fn) => AsyncIterator.from(regExp(str, pat)).some(fn);

但是,如果这不符合您的要求,您实际上可以为整个逻辑使用生成器函数yield,其中promise 可能需要await次,然后同步运行(只需跳过输出值并立即将其传回)或异步运行(通过等待输出值并传递/抛回其结果):

function regExp*(str, pat, fn) {
  let loc = 0;
  let res;
  while((res = pat.exec(str.substring(loc)))){
    const rtn = yield fn(res);
    if(rtn) return rtn;
    loc += res.length + res.index;
  }
}
function syncRun(generatorFn) {
  return function(...args) {
    const generator = generatorFn.apply(this, args);
    let result = {done: false, value: undefined};
    while (!result.done) {
      result = generator.next(result.value);
    }
    return result.value;
  };
}
function asyncRun(generatorFn) {
  return async function(...args) {
    const generator = generatorFn.apply(this, args);
    let method = "next", done = false, value = undefined;
    while (!done) {
      ({value, done} = generator[method](value));
      [method, value] = await Promise.resolve(value).then(
        result => ["next", result],
        error => ["throw", error]
      );
    }
    return value;
  };
}

const regExpSync = syncRun(regExp);
const regExpAsync = asyncRun(regExp);

Javascript相关问答推荐

Codemirsor 6语言包的使用部分是什么?

IOS(React Native)中未找到模块SquareReaderSDK

输入有关HTML复选框的已判断属性的信息

添加/删除时React图像上传重新渲染上传的图像

无法将nPM simplex-noise包导入在JS项目中工作

使用print This时, map 容器已在LeafletJS中初始化

当在select中 Select 选项时,我必须禁用不匹配的 Select

模块与独立组件

Snowflake JavaScript存储过程返回成功,尽管预期失败

Next.js(react)使用moment或不使用日期和时间格式

为什么useState触发具有相同值的呈现

JQuery Click事件不适用于动态创建的按钮

OpenAI转录API错误请求

是否可以将Select()和Sample()与Mongoose结合使用?

当我点击一个按钮后按回车键时,如何阻止它再次被点击

React:防止useContext重新渲染整个应用程序或在组件之间共享数据而不重新渲染所有组件

Reaction useState和useLoaderData的组合使用引发无限循环错误

如何在Jest中模拟函数

select 2-删除js插入的项目将其保留为选项

未捕获的不变违规:即使在使用DndProvider之后也应使用拖放上下文