javascript - 如何调用函数,但在有值之前不接收响应?

标签 javascript

我有一个查询 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/

相关文章:

javascript - 创建一个以变量作为字段的 JSON 对象

javascript - 使用 JQuery 调整/强制 Z 索引

javascript - JQuery Mobile 中的分页符?

javascript - Yii2 验证码刷新或重新加载图像

javascript - Bootstrap 开关未切换

javascript - 为什么数组的索引在下面的代码中是一个字符串?

javascript - 无需使用鼠标即可选中和取消选中控件,因为当我们按下 Enter 键时,按钮控件就会被触发

HTML 文件中的 javascript 调试

javascript - JavaScript音频输入

javascript - javascript 文件中的 Ajax-Post-Data-maxJsonLength-property-limit-execeed