javascript:.replace 中的异步/等待
Posted
技术标签:
【中文标题】javascript:.replace 中的异步/等待【英文标题】:javascript : Async/await in .replace 【发布时间】:2016-02-11 09:25:17 【问题描述】:我正在通过以下方式使用 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
函数的返回值始终是一个 Promise 对象,该对象使用返回的 output
进行解析(或拒绝并抛出错误)。
您想知道为什么output
是一个承诺吗?我不清楚你的问题是什么。请注意,如果string.replace
的字面意思是String.prototype.replace
,那么这是行不通的。 .replace
期望回调是普通函数,而不是异步函数。
【参考方案1】:
一个易于使用和理解的异步替换功能:
async function replaceAsync(str, regex, asyncFn)
const promises = [];
str.replace(regex, (match, ...args) =>
const promise = asyncFn(match, ...args);
promises.push(promise);
);
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 迭代匹配项时有效。这不适用于替换。 确实如此。它迭代和替换。 我真的很喜欢这个解决方案,又好又简单!【参考方案2】:native replace
method 不处理异步回调,您不能将它与返回承诺的替换器一起使用。
不过,我们可以编写自己的 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("");
);
【讨论】:
【参考方案3】:因此,没有需要承诺的替换过载。因此,只需重述您的代码:
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("");
【讨论】:
我已经更新了这个问题。我需要将匹配的元素传递给函数,所以这种方式无法完成。 @ritz078 我以为你可能错过了。也许我的编辑更有用?以上是关于javascript:.replace 中的异步/等待的主要内容,如果未能解决你的问题,请参考以下文章
JavaScript replace() 方法转换时间数据中的“-”和“/”
深入理解 JavaScript 中的 replace 方法(转)
.replace 不是 javascript 中的函数错误 [重复]