首页 > 解决方案 > 如何将异步函数值传递给事件处理程序

问题描述

我正在获取样式表并将所有 CSS 变量替换为当用户根据需要更改颜色时它对应的实际十六进制值。

我创建了一个事件处理程序,以便当用户单击下载按钮时,他/她选择的所有颜色都将保存在样式表中,但它似乎不起作用。我知道这是我对整个承诺的理解的问题async await

我做了什么。

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()

我不能awaitupdated_css因为它属于点击事件的回调,这是一个新功能。

然后我做了以下认为它会起作用,因为它是顶级的。

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')
})

这给了我以下错误TypeError: NetworkError when attempting to fetch resource.

我知道调用fetchStyleSheet()一开始只返回一个promise对象并且要获取值(即updated_css),我需要跟随它.then()await它。

标签: javascriptpromiseasync-awaitdom-events

解决方案


await是处理fetchStyleSheet()返回承诺的调用的正确方法,您的问题是单击链接会尝试href立即遵循该属性 -您将其设置为该数据 url 之前。相反,您需要做的是阻止默认操作,异步执行您的操作,然后在完成后重新触发单击。也不要忘记处理可能的异常:

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
  }
})

推荐阅读