javascript - 如何在javascript中等待具有超时的元素
问题描述
我正在寻找一种方法来等待元素在 DOM 中显示并在给定时间内未显示时抛出超时异常。我怎样才能做到这一点?我有这个想法,但肯定它不会起作用。
function waitForElement(element, timeout) {
return new Promise((resolve, reject) => {
const t = setTimeout(() => {
let queryInterval = setInterval(() => {
const isElementVisible = document.contains(element);
if (!isElementVisible) {
clearInterval(queryInterval);
clearTimeout(t);
resolve(true);
}
}, 10);
console.log("Timeout!");
clearTimeout(t);
reject("Time Out!");
}, timeout);
});
}
解决方案
查看突变观察者 api。
这是一个示例实现,它返回一个 Promise,如果该节点未在分配的时间内出现,则该 Promise 要么使用添加的节点进行解析,要么拒绝。
它通过设置一个 MutationObserver 来监视是否出现通过给定的testFn
. 它设置了一个超时,断开观察者的连接并在给定的时间后拒绝。如果观察者在超时到期之前看到节点出现,它会清除超时并与节点一起解决。
// Waits for a node that passes testFn to appear and returns it.
// Gives up and rejects after 'wait' ms.
// Returns a Promise that resolves with the found node.
const waitForElement = (testFn, wait = 1000) => {
return new Promise((resolve, reject) => {
// create an observer using onDomChange (defined below)
const observer = new MutationObserver(onDomChange);
// watch the container for childList changes
observer.observe(container, {
childList: true
});
// set a countdown to give up and reject
const timeout = setTimeout(
() => {
// when the timeout expires, stop watching…
observer.disconnect();
// and reject
reject('Never showed up.')
},
wait // how long to wait before rejecting
);
// the callback for observed dom changes
function onDomChange(mutations, observer) {
// find an addedNode that passes the testFn in the mutations
const node = mutations.map(m => [...m.addedNodes]).flat().find(testFn);
// if we find a match…
if (node) {
// stop the rejection timeout
clearTimeout(timeout);
// stop observing
observer.disconnect();
// and resolve with the found node
resolve(node);
}
}
});
}
// convenience for creating a div with the given text
const d = (text) => {
const el = document.createElement('div');
el.className = 'bananas';
el.innerText = text;
return el;
}
// test the waitForElement with the given delay
async function go(delay) {
const container = document.getElementById('container');
// wait for the specified duration before adding a div with the delay as the text
setTimeout(() => container.appendChild(d(delay)), delay);
try {
// wait for the element to appear
const el = await waitForElement(n => n.innerText.endsWith(delay));
// append some text to the content
el.innerText += ' - found it.'
// add a css class
el.classList.add('found');
} catch (e) {
// log an error if it didn't appear in time
console.error(`rejected for ${delay}`);
}
}
// default wait time is 1000ms, so…
go(300); // under the 1000ms wait time. finds it.
go(5000); // takes too long. rejects
go(100); // finds it.
go(600); // finds it.
go(3000); // rejects
.bananas {
margin-bottom: .5em;
padding: 0.25em;
background: #ffff99;
}
.found {
background: tomato;
color: bisque;
}
<div id="container"></div>
推荐阅读
- r - 在 data.table 中执行 for 循环
- sql - 将表 B 连接到表 A,其中表 B 是审计历史记录,并且只需要表 A 上某个日期之前的最新表 B 条目
- swift - URLSession.shared.uploadTask 完成后继续代码
- typescript - redux 根减速器的返回类型
- algorithm - 如何改进我的“旋转(滚动/循环排列)阵列”解决方案?
- django - Postgresql 通过 sql 脚本更新,在后端获取通知
- css - MS Edge 上的 CSS 边框问题
- python - 您如何为实时系统实现 Python Gekko 应用程序?
- windows - Windows 10:将 Acrobat Reader 设置为批处理文件中的默认 PDF 阅读器
- android - 有没有办法通过来自服务器的 API 来监听 json 的变化?