Jsdom如何“轮询特定元素的存在”?

时间:2019-04-22 21:43:34

标签: typescript jsdom

在jsdom docs 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")
      );
...

尽管我知道此元素最终将被加载,但这会导致无限循环。似乎该参数可能第一次被评估为null,然后在以后的每个时间都被设置为null,但我不确定。无论如何,我也尝试使用

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

并检查所得的收集长度不为0,但这将返回相同的无限循环。我认为dom选择器方法不是问题。那么,是什么导致这个无限循环,和/或有没有更好的方法来轮询元素?

1 个答案:

答案 0 :(得分:1)

这里有一些误解:

  1. elementOnPage(querySelector(...))的调用一次 执行(除非代码本身位于某个循环或事件处理程序中)。如果DOM元素在执行时存在,它将立即返回,否则它将不再执行选择器,因此您的函数将以null作为给出的参数无限地运行。

  2. 在JavaScript中,while之类的循环正在阻塞(不包括此处无关的工作器),因此您基本上是在锁定线程。即使您从循环内部重新运行querySelector,也会导致无限循环。

要执行轮询而不阻止JS执行,您想使用setIntervalsetTimeout

另外,一个等待的函数应该返回Promise(从技术上讲,您可以await进行任何操作,但是使用promise可以使它有用)。

这是一个未经测试的示例:

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");