你不希望使用繁忙等待,因为这会阻止其他JavaScript代码运行(更不用说浏览器UI的大部分),导致该属性无法被定义。
理想情况下,提供该属性的任何内容都应该有一个事件可以触发,您可以将其挂钩到其中。我假设您已经查找并未找到。
一旦ECMAScript6(又名“ES6”)中最新内容的支持变得普遍(目前尚未实现),您可能能够在此使用Proxy
(如果您的目标浏览器允许在其HTML元素实例上使用Proxy
)。但是,对于Proxy
的广泛支持需要几年时间,如果不是更长时间(并且不能使用shim/polyfill来模拟Proxy
)。 (在ES7中,您可以使用Object.observe
,但是假定在ES7技术出现之前,由当前[截至2015年6月]标准定义的Proxy
将得到广泛支持。)
在能够使用Proxy
之前/之后,计时器确实是处理此情况的正确方法。如果需要,它可以是一个非常激进的计时器。
如果已知元素存在但正在等待属性:
check(function(element) {
});
function check(callback) {
var element = document.querySelector('#embed-container #mf2-events');
if (element && 'jsMF2' in element) {
setTimeout(callback.bind(null, element), 0);
} else {
setTimeout(check.bind(null, callback), 0);
}
}
大多数浏览器在javascript线程可用的前几次会立即触发计时器,然后将其限制为至少4ms的延迟以供后续调用。仍然相当快。
不过你不必过于激进;与计算机相比,人类很慢,你可能可以使用10、20或甚至50毫秒。
如果存在任何属性不会出现的可能性,最终你需要停止重复的setTimeout
序列(一秒钟后,十秒钟后,三十秒钟后,六十秒钟后,适合你使用情况的时间)。你可以通过记住启动时间,并在等待时间太长时放弃而不是重新安排来实现这一点:
var started = Date.now();
check(function(element) {
});
function check(callback) {
var element = document.querySelector('#embed-container #mf2-events');
if (element && 'jsMF2' in element) {
setTimeout(callback.bind(null, element), 0);
} else {
if (Date.now() - started > 1000) {
} else {
setTimeout(check.bind(null, callback), 0);
}
}
}
侧记:查询语句
var document.querySelector('#embed-container #mf2-events');
这有点奇怪。它说:“给我第一个在具有
id
embed-container
的元素内找到的带有
id
mf2-events
的元素。”但是在页面上,
id
值
必须是唯一的。因此,它实际上只是说:“获取
#mfs-events
元素,但仅当它在
#embed-container
元素内部时。”
除非这真的是你想要的,否则会更快。
var document.getElementById('mf2-events');
这是一个很好的选择。
setTimeout()
进行轮询,或者在现代浏览器中使用MutationObserver
。在while
循环中旋转只会锁定浏览器,并且永远无法成功,因为没有其他代码可以运行以实际引起更改。 - jfriend00