Javascript : Async/await In .replace
I am using the async/await function the following way async function(){ let output = await string.replace(regex, async (match)=>{ let data = await someFunction(match)
Solution 1:
An easy function to use and understand for some async replace :
asyncfunctionreplaceAsync(str, regex, asyncFn) {
const promises = [];
str.replace(regex, (match, ...args) => {
const promise = asyncFn(match, ...args);
promises.push(promise);
});
const data = awaitPromise.all(promises);
return str.replace(regex, () => data.shift());
}
It does the replace function twice so watch out if you do something heavy to process. For most usages though, it's pretty handy.
Use it like this:
replaceAsync(myString, /someregex/g, myAsyncFn)
.then(replacedString =>console.log(replacedString))
Or this:
const replacedString = awaitreplaceAsync(myString, /someregex/g, myAsyncFn);
Don't forget that your myAsyncFn
has to return a promise.
An example of asyncFunction :
asyncfunctionmyAsyncFn(match) {
// match is an url for example.const fetchedJson = awaitfetch(match).then(r => r.json());
return fetchedJson['date'];
}
functionmyAsyncFn(match) {
// match is a filereturnnewPromise((resolve, reject) => {
fs.readFile(match, (err, data) => {
if (err) returnreject(err);
resolve(data.toString())
});
});
}
Solution 2:
The native replace
method does not deal with asynchronous callbacks, you cannot use it with a replacer that returns a promise.
We can however write our own replace
function that deals with promises:
asyncfunction(){
return string.replace(regex, async (match)=>{
let data = awaitsomeFunction(match)
console.log(data); //gives correct datareturn data;
})
}
functionreplaceAsync(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 matchif (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));
returnPromise.all(parts).then(function(strings) {
return strings.join("");
});
}
Solution 3:
So, there's no overload of replace that takes a promise. So simply restate your code:
asyncfunction(){
let data = await someFunction();
let output = string.replace(regex, data)
return output;
}
of course, if you need to use the match value to pass to the asynchronous function, things get a bit more complicated:
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 reusedwhile((mtch = rx.exec(sourceString)) != null)
{
//gather all of the matches up-front
matches.push(mtch);
}
//now apply async function someFunction to each matchvar 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 = awaitPromise.all(promises);
//split the source string by the regex,//so we have an array of the parts that weren't matchedvar 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("");
Post a Comment for "Javascript : Async/await In .replace"