Jsdom, как "опросить на наличие определенного элемента"? - PullRequest
0 голосов
/ 23 апреля 2019

В документах jsdom https://github.com/jsdom/jsdom, при асинхронной загрузке скрипта рекомендуется опросить наличие определенного элемента, чтобы убедиться, что dom загружает то, что вам нужно.

Приведенный ниже код является моей интерпретацией:

const elementOnPage = (arg: HTMLElement | null): HTMLElement => {
  let tried = arg;
  while (tried === null) {
    // debugger;
    console.log("nothing yet");
    tried = arg;
  }
  return tried;
};

затем вызовите функцию следующим образом:

...
await elementOnPage(
        dom.window.document.querySelector("#some element that I know will eventually be loaded onto the page")
      );
...

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

dom.window.document.getElementsByClassName("some class that will eventually have member elements")

и проверка, что полученная длина коллекции не равна 0, но это возвращает тот же бесконечный цикл. Я не думаю, что метод выбора DOM является проблемой. Итак, что вызывает этот бесконечный цикл и / или есть ли лучший способ опроса элемента?

1 Ответ

1 голос
/ 23 апреля 2019

Здесь есть несколько недоразумений:

  1. Вызов elementOnPage(querySelector(...)) выполняется один раз (если только этот код не находится в каком-либо цикле или обработчике события).Если элемент DOM существует во время выполнения, он немедленно возвращается, в противном случае он никогда больше не выполнит селектор, поэтому ваша функция будет бесконечно работать с null в качестве аргумента, который ему был задан.

  2. В JavaScript циклы, подобные while, блокируются (не считая рабочих, которые здесь не связаны), поэтому вы в основном блокируете поток.Даже если вы перезапустите querySelector из цикла, это приведет к бесконечному циклу.

Для выполнения опроса без блокировки выполнения JS вы хотите использовать setInterval или setTimeout.

Кроме того, ожидаемая функция должна возвращать Promise (технически вы можете await что угодно, но обещание - это ваш способ сделатьэто полезно).

Вот непроверенный пример:

const elementOnPage = (query: string, timeout: number = 10000): Promise<HTMLElement | null> => {
  return new Promise((resolve, reject) => {
    const startTime = Date.now();
    const tryQuery = () => {
      const elem = dom.window.document.querySelector(query);
      if (elem) resolve(elem); // Found the element
      else if (Date.now() - startTime > timeout) resolve(null); // Give up eventually
      else setTimeout(tryQuery, 10); // check again every 10ms
    }
    tryQuery(); // Initial check
  });
};


// Elsewhere:
const elem = await elementOnPage("#some_element");
...