Reputation: 399
I have an async function that I would like to return a value from and then use.
Within the updatedStyleSheet
function, I'd like to return the updated_css
so that I can use it somewhere else.
async function updatedStyleSheet() {
const res = await fetch("./prism.css");
const orig_css = await res.text();
let updated_css = orig_css;
const regexp = /(?:var\(--)[a-zA-z\-]*(?:\))/g;
let cssVars = orig_css.matchAll(regexp);
cssVars = Array.from(cssVars).flat();
for (const v of cssVars) {
updated_css = updated_css.replace(v, colors[v.slice(6, -1)]);
};
// return updated_css ?
}
If I call this function, I get a Promise object. Rightfully so, since async functions always return a promise.
Could I return the updated_css
within the updatedStyleSheet
function and do something like this after?
const newSheet = updatedStyleSheet().then(css => css)
Then use the newSheet
variable wherever in my script?
End Goal
Take the updated_css
that contains the text contents of my CSS and use it as an href
value so the user can download the stylesheet.
Edit
I attempted to add an event handler so that all the selected color values would be saved in the stylesheet once the user saves it, but it doesn't seem to work. I know it is still an issue with my understanding of promises as a whole.
What I did.
const updatedStyleSheet = async () => {
const res = await fetch("./themes/prism.css");
const orig_css = await res.text();
let updated_css = orig_css;
const regexp = /(?:var\(--)[a-zA-z\-]*(?:\))/g;
let cssVars = orig_css.matchAll(regexp);
cssVars = Array.from(cssVars).flat();
console.log(cssVars)
for await (const variable of cssVars) {
const trimmedVar = variable.slice(6, -1)
const styles = getComputedStyle(document.documentElement)
const value = String(styles.getPropertyValue(`--${trimmedVar}`)).trim()
updated_css = updated_css.replace(variable, value);
}
console.log(updated_css)
return updated_css
}
const main = async () => {
const downloadBtn = document.getElementById('download-btn')
downloadBtn.addEventListener('click', () => {
const updated_css = updatedStyleSheet()
downloadBtn.setAttribute('href', 'data:application/octet-stream;charset=utf-8,' + encodeURIComponent(updated_css))
downloadBtn.setAttribute('download', 'prism-theme.css')
})
}
main()
I can't await
the updated_css
because it falls into the callback of the click event, which is a new function.
Then I did the following thinking it would work since it was top level.
const downloadBtn = document.getElementById('download-btn')
downloadBtn.addEventListener('click', async () => {
const updated_css = await updatedStyleSheet()
downloadBtn.setAttribute('href', 'data:application/octet-stream;charset=utf-8,' + encodeURIComponent(updated_css))
downloadBtn.setAttribute('download', 'prism-theme.css')
})
That gave me the following error TypeError: NetworkError when attempting to fetch resource.
Upvotes: 1
Views: 492
Reputation: 1306
Yes. Since you're already using async/await
, just create a top level async
function, say main
, and use the returned updated_css
content after awating the promise to resolve:
async main() {
const updated_css = await updatedStyleSheet()
// use css as you please
}
// run program
main()
Don't mind the cost of one more function call.
Upvotes: 1
Reputation: 5789
If you need to wait for an async function to return a value (so that you can use this value afterwards), use the await
keyword:
const newSheet = await updatedStyleSheet()
However, mind that awaiting blocks the execution until the function returns. This might not be the behaviour you want.
Upvotes: 0
Reputation: 1148
I would collapse the promise by using the .then() function EX:
var bar = updatedStyleSheet()
bar.then(updated_css=>{
//logic goes here
});
Upvotes: 1