Как передать значение функции asyn c в обработчик событий - PullRequest
0 голосов
/ 19 января 2020

Я извлекаю таблицу стилей и заменяю все переменные 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()

Я не могу await updated_css потому что он попадает в функцию обратного вызова события click, которое является новой функцией.

Затем я решил, что это сработает, поскольку это был верхний уровень.

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() сначала только возвращает объект обещания и получает значение (равное updated_css) Мне нужно следовать за этим с .then() или await.

1 Ответ

1 голос
/ 19 января 2020

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