我按以下方式使用 async/await 函数
async function(){
let output = await string.replace(regex, async (match)=>{
let data = await someFunction(match)
console.log(data); //gives correct data
return data
})
return output;
}
但是返回的数据是一个promise对象。只是对如何在带有回调的函数中实现它感到困惑。
一个易于使用和理解的异步替换函数:
async function replaceAsync(str, regex, asyncFn) {
const promises = [];
str.replace(regex, (...args) => {
promises.push(asyncFn(...args));
});
const data = await Promise.all(promises);
return str.replace(regex, () => data.shift());
}
它会执行两次替换功能,因此请注意您是否执行了繁重的处理操作。但对于大多数用途来说,它非常方便。
像这样使用它:
replaceAsync(myString, /someregex/g, myAsyncFn)
.then(replacedString => console.log(replacedString))
或者这个:
const replacedString = await replaceAsync(myString, /someregex/g, myAsyncFn);
不要忘记你的
myAsyncFn
必须返回一个承诺。
asyncFunction 的示例:
async function myAsyncFn(match) {
// match is an url for example.
const fetchedJson = await fetch(match).then(r => r.json());
return fetchedJson['date'];
}
function myAsyncFn(match) {
// match is a file
return new Promise((resolve, reject) => {
fs.readFile(match, (err, data) => {
if (err) return reject(err);
resolve(data.toString())
});
});
}
replace
方法不处理异步回调,你不能将它与返回promise的替换器一起使用。
但是我们可以编写自己的
replace
函数来处理 Promise:
async function(){
return string.replace(regex, async (match)=>{
let data = await someFunction(match)
console.log(data); //gives correct data
return data;
})
}
function replaceAsync(str, re, callback) {
// http://es5.github.io/#x15.5.4.11
str = String(str);
var parts = [],
i = 0;
if (Object.prototype.toString.call(re) == "[object RegExp]") {
if (re.global)
re.lastIndex = i;
var m;
while (m = re.exec(str)) {
var args = m.concat([m.index, m.input]);
parts.push(str.slice(i, m.index), callback.apply(null, args));
i = re.lastIndex;
if (!re.global)
break; // for non-global regexes only take the first match
if (m[0].length == 0)
re.lastIndex++;
}
} else {
re = String(re);
i = str.indexOf(re);
parts.push(str.slice(0, i), callback.apply(null, [re, i, str]));
i += re.length;
}
parts.push(str.slice(i));
return Promise.all(parts).then(function(strings) {
return strings.join("");
});
}
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++]);
}
这需要更新的浏览器基线,因为
String.prototype.matchAll
,它于 2019 年全面落地(Edge 除外,它在 2020 年初通过基于 Chromium 的 Edge 获得了它)。但它至少同样简单,同时也更高效,仅在第一次进行“匹配”,而不是创建无用的字符串,也不会以昂贵的方式改变替换数组。
因此,不存在需要承诺的重载替换。因此,只需重申您的代码:async function(){
let data = await someFunction();
let output = string.replace(regex, data)
return output;
}
当然,如果你需要使用匹配值传递给异步函数,事情会变得有点复杂:
var sourceString = "sheepfoohelloworldgoocat";
var rx = /.o+/g;
var matches = [];
var mtch;
rx.lastIndex = 0; //play it safe... this regex might have state if it's reused
while((mtch = rx.exec(sourceString)) != null)
{
//gather all of the matches up-front
matches.push(mtch);
}
//now apply async function someFunction to each match
var promises = matches.map(m => someFunction(m));
//so we have an array of promises to wait for...
//you might prefer a loop with await in it so that
//you don't hit up your async resource with all
//these values in one big thrash...
var values = await Promise.all(promises);
//split the source string by the regex,
//so we have an array of the parts that weren't matched
var parts = sourceString.split(rx);
//now let's weave all the parts back together...
var outputArray = [];
outputArray.push(parts[0]);
values.forEach((v, i) => {
outputArray.push(v);
outputArray.push(parts[i + 1]);
});
//then join them back to a string... voila!
var result = outputArray.join("");
这是 Overcl9ck 在 TypeScript 中实现的解决方案:
const replaceAsync = async (str: string, regex: RegExp, asyncFn: (match: any, ...args: any) => Promise<any>) => {
const promises: Promise<any>[] = []
str.replace(regex, (match, ...args) => {
promises.push(asyncFn(match, ...args))
return match
})
const data = await Promise.all(promises)
return str.replace(regex, () => data.shift())
}
这是一种使用递归函数的替代方法:
async function replaceAsync(str, regex, asyncFn) {
const matches = str.match(regex);
if (matches) {
const replacement = await asyncFn(...matches);
str = str.replace(matches[0], replacement);
str = await replaceAsync(str, regex, asyncFn);
}
return str;
}
还有另一个解决方案,这次是使用 TypeScript。与
replace()
来代替,避免了许多其他解决方案中“语义上不寻常”的初始 match()
调用。
async function replaceAsync(str: string, regex: RegExp, asyncFn: (match: string) => Promise<string>): Promise<string> {
const promises = (str.match(regex) ?? []).map((match: string) => asyncFn(match));
const data = await Promise.all(promises);
return str.replace(regex, () => data.shift()!);
}