我有一个查询 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 中之前调用此函数。这就是为什么如果我每半秒左右检查一次,数组将在几秒钟内存在并且我可以将其发回。
我的问题是,是否有一个我应该遵循的既定模式允许调用一个函数,但在有一个函数之前不会收到返回值?
最佳答案
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 }
<div id="main"></div>
将 MutationObserver
驯服到一个健全的 API 中
我们可以制作我们自己的 nextMutation
函数,它接受一个文档查询选择器并返回下一个添加的 child 的 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)
<div id="main"></div>
等待太久超时
上面的 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
<div id="main"></div>
关于javascript - 如何调用函数,但在有值之前不接收响应?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44425267/