Обещание разрешено, но код останавливается в ожидании - PullRequest
0 голосов
/ 17 января 2020

Я следовал за документами Мозиллы . Я создал функцию с Promise внутри. Promise разрешается, когда на странице появляется селектор (если нет, функция запускается снова). Затем код должен продолжаться после await:

;(async () => {
  const titleSel = '.playbackSoundBadge__titleLink'
  document.querySelector(titleSel).click()
  const moreSel = 'button[title="More"]'
  await waitForEl(moreSel)
  console.log('after await')

  function waitForEl(selector) {
    return new Promise(resolve => {
      console.log(selector)
      if (document.querySelector(selector)) {
        console.log('resolved')
        resolve('resolved')
      } else {
        console.log('rejected')
        setTimeout(() => {
          waitForEl(selector)
        }, 100)
      }
    })
  }
})()

Но, как ни странно, 'resolved' регистрируется. Но код после await не запускается. Другими словами, 'after await' никогда не регистрируется.

Почему это так и как это исправить?

Ответы [ 2 ]

2 голосов
/ 17 января 2020

Но, как ни странно, «решено» регистрируется.
...
Почему это

waitForEl называется «рекурсивно» (оно планирует вызов сам через setTimeout). Каждый вызов waitForEl создает обещание, поэтому вы создаете несколько обещаний. «Разрешение», которое вы видите в консоли, происходит от одного из этих обещаний. Вы также должны увидеть одно или несколько сообщений 'reject'.

Проблема в том, что обещание "parent" / "top" никогда не разрешается, потому что здесь ничего не делается с возвращаемым значением:

waitForEl(selector)

Функция возвращает обещание, но вы ничего с ним не делаете, поэтому никогда не разрешаете обещание, вызвавшее эту функцию.

Простое решение будет

waitForEl(selector).then(resolve)

Но это также означает, что вы создаете обещания рекурсивно. Кажется, нет необходимости делать это. Просто определите простую функцию внутри обещания, которое вызывает само себя:

 function waitForEl(selector) {
    return new Promise(resolve => {
      console.log(selector)
      (function check()
        if (document.querySelector(selector)) {
          console.log('resolved')
          resolve('resolved')
        } else {
          console.log('rejected')
          setTimeout(check, 100);
        }
      }());
    })
  }

Вы все равно должны добавить некоторое условие, которое через некоторое время отклонит обещание, чтобы оно не вызывало setTimeout навсегда.

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

Вы должны передать waitForEl(selector) на resolve:

;(async () => {
  const moreSel = '.more'
  await waitForEl(moreSel)
  console.log('after await')

  function waitForEl(selector) {
    return new Promise(resolve => {
      console.log(selector)
      if (document.querySelector(selector)) {
        console.log('resolved')
        resolve('resolved')
      } else {
        console.log('rejected')
        setTimeout(() => {
          resolve(waitForEl(selector)) // here
        }, 1000)
      }
    })
  }
})()

const btn = document.createElement("button");
btn.textContent = "add more";
const more = document.createElement("div");
more.textContent = "more";
more.classList.add("more");
btn.addEventListener("click", () => {
  document.body.appendChild(more);
});
document.body.appendChild(btn);

В вашем коде await waitForEl(moreSel) никогда не устанавливался, поэтому невозможно выполнить приведенный ниже журнал. Если вы передадите обещание resolve, первоначальное обещание «свяжет» его судьбу с прошедшим.

...