I am trying out a Chrome extension.
How do I get a replaceAll‘s callback function to use await ?
window.onload = async () =>
{
const elem = document.getElementById('#myID');
const elem_modified = elem.replaceAll(regex, await myFunction);
document.getElementById('#myID').innerHTML = elem_modified;
}
myFunction :
const myFunction = async (str) =>
{
const items = [...str.matchAll(regex)][0];
// Do some manipulation
let amount = number * value;
const amount_modified = await calculate(amount);
console.log("amount_modified = " + amount_modified); // This shows correctly
return items[0] + ' (' + amount_modified + ')';
}
The result is like
over [object Promise] to many people
>Solution :
You don’t, replaceAll — like lots of functions that support callbacks — doesn’t expect a promise as a return value from the callback. In the vast majority of cases, you can’t usefully pass a promise to code that doesn’t expect one. (map is one exception to that rule.)
You haven’t provided a runnable example or an example of your regular expression, but the general shape of the solution here will be:
- Split the string into parts (the segments you want to pass through your
asyncfunction and the segments between them). - Start the calculation for each of the segments you want to process and get a promise (from your
asyncfunction) of the result; for the segments in-between, just create a promise fulfilled to the original segment value. - Wait for all of those to complete by using
Promise.all,awaiting the promise it provides. (That’s assuming it’s okay to start processing all the segments at once, rather than waiting for the processing of one to end before starting processing the next.) - Assemble a new string from the updated segments and the segments that used to be between them.
Here’s a rough sketch that isolates the numbers in a string and builds a new string with the numbers doubled. This version doesn’t, of course, need to be async at all, but you can substitute a truly async operation for calculate:
async function calculate(str) {
await new Promise((resolve) => setTimeout(resolve, 10)); // Just so we do actually do something async
return str ? String(Number(str) * 2) : str;
}
async function example(str) {
const rex1 = /(\d+)/; // Note the capture group, so `split` retains the delimiter between matches
const rex2 = /^\d+$/; // Same as above, but full string match and no capture group
// #1
const parts = str.split(rex1);
// #2 and #3 (the `await`)
const updated = await Promise.all(parts.map(async (part) => {
if (rex2.test(part)) {
return await calculate(part);
}
return part;
}));
// #4
return updated.join("");
}
example("Testing 1 2 3 testing")
.then((result) => console.log(result))
.catch((error) => console.error(error));
Side note: The DOM event system won’t pay any attention to the promise the async function you’re using as an event handler returns, so it’s important not to allow any errors (promise rejections) to terminate that handler, since those rejections will be unhandled.