我有一个查询DOM的函数,并返回一个数据属性数组。
var getUIDs = function () {
$list = $('.foo');
if ( $list.length ) {
// loop through all the .foos and build an array
return fooArray;
} else {
setTimeout(function(){
getUIDs()
}, 500);
}
}
有时可以在.foo
出现在DOM之前调用此函数。这就是为什么如果我检查每半秒左右,在几秒钟内阵列就会存在,我可以把它发回去。
我的问题是,是否存在我应遵循的既定模式,允许调用函数,但在有函数之前不会收到返回值?
答案 0 :(得分:1)
<强> MutationObserver
强>
这是使用MutationObserver
进行的演示 - 但它是非常裸露的金属并且难以与之互动。如果我们想要使用它,我们想要自己的功能来抽象出一些复杂性
var target =
document.getElementById('main')
var observer =
new MutationObserver(muts =>
muts.forEach(m => console.log(m)))
observer.observe(target, {childList: true});
setTimeout(() => {
var span1 = document.createElement('span')
span1.textContent = 'cat'
target.appendChild(span1)
}, 1000)
// { Mutation }
&#13;
<div id="main"></div>
&#13;
将MutationObserver
驯服为合理的API
我们可以创建自己的nextMutation
函数,它接受文档查询选择器并返回下一个添加子项的Promise
const nextMutation = sel =>
new Promise((resolve,_) => {
const obs = new MutationObserver(muts => {
for (const {addedNodes} of muts)
if (addedNodes.length > 0) {
resolve(addedNodes[0])
obs.disconnect() // stop observing
return // stop iterating
}
})
obs.observe(document.querySelector(sel), {childList: true})
})
// demo mutation: add some element to #main in 1 second
setTimeout(() => {
var span1 = document.createElement('span')
span1.textContent = 'cat'
document.querySelector('#main').appendChild(span1)
}, 1000)
nextMutation('#main')
.then(child => console.log('added child', child)) // added child: <span>cat</span>
.catch(console.error)
&#13;
<div id="main"></div>
&#13;
等待太久后
超时
以上nextMutation
将无限期地等待,直到将子节点添加到目标。如果孩子在X
秒内没有添加,我们想吐出错误怎么办?当然,我们可以增加nextMutation
函数来执行此操作
此代码段还演示了您可以将多个观察者附加到同一目标。下面,在domReady之后1秒将元素添加到目标。等待最多2秒的观察者将成功捕获此突变 - 但是,仅等待0.5秒的观察者将因为未观察到突变而引发错误
const nextMutation = sel =>
new Promise((resolve, reject) => {
const obs = new MutationObserver(muts => {
for (const {addedNodes} of muts)
if (addedNodes.length > 0) {
resolve(addedNodes[0])
obs.disconnect()
return
}
})
obs.observe(document.querySelector(sel), {childList: true})
})
const awaitNextMutation = (sel, ms) =>
Promise.race([
nextMutation(sel),
new Promise((_,reject) =>
setTimeout(reject, ms, Error('awaitNextMutation timeout')))
])
// demo mutation: add some element to #main in 1 second
setTimeout(() => {
var span1 = document.createElement('span')
span1.textContent = 'cat'
document.querySelector('#main').appendChild(span1)
}, 1000)
// wait for up to 2 seconds; since the child is added within
// 1 second, this promise will resolve just fine
awaitNextMutation('#main', 2000)
.then(child => console.log('added child', child)) // added child: <span>cat</span>
.catch(console.error)
// this one only waits 500 ms so an Error will throw
awaitNextMutation('#main', 500)
.then(child => console.log('added child', child))
.catch(console.error) // => Error awaitNextMutation timeout
&#13;
<div id="main"></div>
&#13;
答案 1 :(得分:0)
我相信soup.find("span", attrs={"class": "description"}).find_next('p')
正是你需要的。
请阅读:https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
答案 2 :(得分:0)
通过顺序执行器nsynjs同步执行此逻辑,可以避免回调,承诺和递归:
function addFooClicked() {
$("#myDiv").append("<div class='foo'>Foo</div>");
}
function synchronousCode() {
var getUIDs = function () {
var foo = $('.foo').get();
while ( foo.length == 0 ) {
console.log("waiting 5 seconds...");
nsynWait(nsynjsCtx,5000);
foo = $('.foo').get();
};
console.log("got elements:",foo.length);
return foo;
};
var res = getUIDs();
console.log("returning...");
return res;
}
nsynjs.run(synchronousCode,{},function(r){
console.log("synchronousCode finished, res=",r);
});
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<script src="https://rawgit.com/amaksr/nsynjs/master/nsynjs.js"></script>
<script src="https://rawgit.com/amaksr/nsynjs/master/wrappers/nsynWait.js"></script>
<body>
<button id="buttonStart" onclick="addFooClicked()">Click me few times</button>
<div id="myDiv"></div>
</body>
&#13;
答案 3 :(得分:-2)
如果您对此进行了贬低,请在评论中解释原因!
您是否希望代码在数据存在之前停止?我看到它的方式,最好的方法是确保数据首先存在。它不像逻辑问题那样真正是一个脚本问题。
在这种情况下,我强烈建议arrive.js在元素到达DOM时添加回调。
在有限情况下可能有用的另类坏方法
另一种方法是在条件满足之前不返回。这将阻止浏览器长达30秒(因此对于面向用户的网站而言非常糟糕),但它可能适合您的情况:
var getUIDs = function () {
$list = $('.foo');
var startTime = new Date().getTime();
var currentTime = startTime;
while ( !$foo.length) {
currentTime = new Date().getTime();
if ( (currentTime - startTime) > 30000 ) {
return null; //or whatever you want to do to indicate an error
}
}
return fooArray;
}