简体   繁体   English

如何将异步函数值传递给事件处理程序

[英]How to pass async function value to an event handler

I'm fetching the stylesheet and replacing all CSS variables with the actual hex value it corresponds to when the user changes the color as desired.当用户根据需要更改颜色时,我正在获取样式表并将所有 CSS 变量替换为它对应的实际十六进制值。

I created an event handler so that when the user clicks the download button, all of the colors he/she selected, would be saved in the stylesheet at that moment, but it doesn't seem to work.我创建了一个事件处理程序,以便当用户单击下载按钮时,他/她选择的所有颜色都将保存在当时的样式表中,但它似乎不起作用。 I know it's an issue with my understanding of promises as a whole and async await我知道这是我对整个承诺和async await理解的问题

What I did.我做了什么。

const fetchStyleSheet = 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 = fetchStyleSheet()
    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.我不能await updated_css因为它属于click事件的回调,这是一个新函数。

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 fetchStyleSheet()
  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.这给了我以下错误TypeError: NetworkError when attempting to fetch resource.

I understand that calling fetchStyleSheet() only returns a promise object at first and to get the value (which is updated_css ), I need to follow it with .then() or await it.我知道调用fetchStyleSheet()只返回一个 promise 对象并获取值(它是updated_css ),我需要使用.then()跟随它或await它。

The await is the correct approach to deal with the fetchStyleSheet() call returning a promise, your problem is that the click on the link tries to follow the href attribute immediately - before you set it to that data url. await是处理返回承诺的fetchStyleSheet()调用的正确方法,您的问题是链接上的点击尝试立即遵循href属性 -您将其设置为该数据 url 之前。 What you would need to do instead is prevent the default action, asynchronously do your stuff, and then re-trigger the click when you're done.您需要做的是阻止默认操作,异步执行您的操作,然后在完成后重新触发点击。 Also don't forget to deal with possible exceptions:也不要忘记处理可能的异常:

const downloadBtn = document.getElementById('download-btn')
downloadBtn.addEventListener('click', async (event) => {
  if (!e.isTrusted) return // do nothing on the second run
  try {
    event.preventDefault()
    const updated_css = await fetchStyleSheet()
    downloadBtn.setAttribute('href', 'data:application/octet-stream;charset=utf-8,' + encodeURIComponent(updated_css))
    downloadBtn.setAttribute('download', 'prism-theme.css')
    downloadBtn.click() // simulate a new click
  } catch(err) {
    console.error(err) // or alert it, or put the message on the page
  }
})

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM