代码之家  ›  专栏  ›  技术社区  ›  Andrew Cheong

如何在半异步情况下使用Javascript async/await?(例如,在String.replace中)[重复]

  •  0
  • Andrew Cheong  · 技术社区  · 10 月前

    例如,我正在对一段文本进行RegExp替换:

      text = text.replace(re, function (match, comment, op1, op2, op3, op4, op5, op6, op7) {
        if (op1 !== undefined) {
          log("processing @@");
          parseEnum(config, op1, args1);
        } else if (op2 !== undefined) {
          log("processing {{}}");
          parseConfig(config, interpolateConfig(config, op2));
          return "";
        } else if (op3 !== undefined && !configOnly) {
          log("processing [[]]");
          return await parseMacro(config, op3, asyncInstances); // <---------- HERE
        } else if (op4 !== undefined) {
          log("processing <<>>");
          await parseInclude(config, interpolateConfig(config, op4)); // <---- HERE
          return "";
        } else if (op5 !== undefined && !configOnly) {
          log("processing ~~~~");
          // TODO parseStyle(op5);
        } else if (op6 !== undefined) {
          log("processing $$");
          return interpolateConfig(config, op6);
        } else if (op7 !== undefined) {
          log("processing ^^");
        }
      });
    
    

    我需要这些替代品 同步 , 对替换函数的每次调用都必须在下一次匹配和替换之前完成。然而,根据比赛的不同,有时我不得不打电话给 async 功能。因此,为了保持同步,我决定使用 等待 。但要做到这一点,我还必须将匿名函数更改为async:

      text = text.replace(re, async function (match, comment, op1, op2, op3, op4, op5, op6, op7) {
                              ++++++
    

    然而,遗憾的是,String.replace不接受异步函数。我找到了 this answer 一个用于实现这一点的实用程序,由@ChrisMorgan逐字复制自该帖子:

    async function replaceAsync(string, regexp, replacerFunction) {
        const replacements = await Promise.all(
            Array.from(string.matchAll(regexp),
                match => replacerFunction(...match)));
        let i = 0;
        return string.replace(regexp, () => replacements[i++]);
    }
    

    这样使用(省略未更改的代码)

      text = await replaceAsync(
          text,
          re,
          async function (match, op1, args1, op2, op3, op4, op5, op6, op7) {
            ...
          }
      );
    

    事实上 似乎 我认为替代品仍然会同步发生——也许这里更好的词是 按顺序 因为在幕后,我们仍然在调用String.replace。一次替换一个。但后来我开始看到奇怪的结果,意识到我错了。替换功能被并行调用,每当当前替换放弃控制时,“未来”替换就开始处理( 例如 获取文件等,这也是某些函数异步的原因)。

    我现在唯一能想到的方法是完全避免async/await,并使用 Promise.resolve() 相反。但我试图在所有地方使用async/await来保持一致的风格。有没有另一种我没有看到的使用async/await的方法?

    更新: 嗯,我也不知道如何使用Promise.resolve()来解决这个问题。我原以为这基本上就像在等待,但事实并非如此。

    1 回复  |  直到 10 月前
        1
  •  2
  •   Ry-    10 月前

    为了解决标题和主题问题:在典型的JavaScript中没有通用的方法。Async/await/epromises与控制流有关,您不能将控制流的会计插入到尚未拥有它的东西中。

    具体而言, String.prototype.replace 不能执行异步操作,以上就是为什么你必须找到一个特定的实现 replaceAsync 那么,关于控制流的特定行为取决于此异步函数的具体实现。它首先为所有替换调用promise返回函数,这通常意味着为每个替换启动单独的并行异步任务:

    const replacements = await Promise.all(
        Array.from(string.matchAll(regexp),
            match => replacerFunction(...match)));
    

    因此,如果你不希望这些任务并行运行,请等到前一个任务完成后再调用下一个任务:

    const replacements = [];
    
    for (const match of string.matchAll(regexp)) {
        replacements.push(await replacerFunction(...match));
    }