async await и dispatchEvent

button.addEventListener("click", function() {
  const ce = new CustomEvent(
    "board:select",
    { bubbles: false, cancelable: true, detail: {} }
  );

  const isCancelled = !document.querySelector(`#${Board.prefix}`)?.dispatchEvent(ce);

  console.log(isCancelled ? "is cancelled" : "is not cancelled");
}

//I вариант
document.querySelector(`#${Board.prefix}`)?.addEventListener("board:select", function() {
  event.preventDefault();
})

//II вариант
document.querySelector(`#${Board.prefix}`)?.addEventListener("board:select", async function() {
  const data = await fetch("http://localhost:4000/boards"); 
  event.preventDefault();
})

Есть простой код, который при нажатии кнопки отсылает событие.

Вопрос - почему в первом варианте isCancelled будет true, во втором будет false.

Хотелось бы дождаться выполнения fetch и уже тогда ставить event.preventDefault(); или не ставить. Сейчас же во втором варианте event.preventDefault(); не отрабатывает.

Подскажите в чем дело?


Ответы (2 шт):

Автор решения: Grundy

dispatchEvent выполняется синхронно, и результат возвращает сразу.

async/await делают функцию асинхронной - и в момент возврата значения функцией dispatchEvent - метод preventDefault еще не был вызван, соответственно и возвращается true

→ Ссылка
Автор решения: Qwertiy
const data = await fetch("http://localhost:4000/boards"); 
event.preventDefault();

Поздно отменять событие, если оно уже произошло.

Хотелось бы дождаться выполнения fetch и уже тогда ставить event.preventDefault(); или не ставить.

Так сделать нельзя, потому что событие рассылается синхронно. Впрочем, в большинстве случаев клик можно повторить программно при необходимости:

var bypassClick = false

document.querySelector("a").addEventListener("click", async e => {
  if (bypassClick) return
  
  e.preventDefault()
  
  var a = e.target.closest("a")
  
  if (a.classList.contains("disabled")) return
  a.classList.add("disabled")

  try {
    if (await shouldBypassClick()) {
      bypassClick = true
      e.target.click()
      bypassClick = false
    } else {
      console.log("Prevented")
    }
  } finally {
    a.classList.remove("disabled")
  }
})

function shouldBypassClick() {
  return new Promise(resolve => setTimeout(resolve, 1000, Math.random() > .5))
}
.disabled {
  opacity: .5;
  pointer-events: none;
}
<a href="data:text/plain,Link%20clicked">Click me</a>

→ Ссылка