例如,我正在对文本正文进行正则表达式替换:
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 函数。因此,为了保持同步,我决定使用 await。但要做到这一点,我还必须将匿名函数更改为异步:
text = text.replace(re, async function (match, comment, op1, op2, op3, op4, op5, op6, op7) {
++++++
不幸的是,String.replace 不接受异步函数。我在这个答案中找到了一个实用程序,可以做到这一点,从@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() 解决这个问题。我认为这本质上会像等待一样,但事实并非如此。这样的东西应该有效
async function x(text){
return 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 ^^");
}
});
}
x(text).then((t)=>{
text = t;
//run further code in here
})
//code here will not have the replaced text
当 Promise 得到解决时,“then”将会被触发。