How to call a function but not receive a response until there is a value?

I have a function that queries the DOM and returns an array of data attributes.

var getUIDs = function () {

    $list = $('.foo');

    if ( $list.length ) {

        // loop through all the .foos and build an array
        return fooArray;

    } else {

        setTimeout(function(){
            getUIDs()
        }, 500);

    }

}

This function can sometimes be called before .foobeing present in the DOM. Therefore, if I check every half second or so, an array will exist within a few seconds, and I can send it back.

My question is, is there an installed pattern that I have to follow that allows the function to be called, but will not get the return value until there is one?

+4
source share
4 answers

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>
Hide result

MutationObserver API

nextMutation,

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>
Hide result

nextMutation , node. , , X ? , nextMutation,

, . 1 domReady. , 2 , - , .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>
Hide result
+1

, promises , 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);
});
<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>
Hide result

0

, , !

, , ? , , , . , .

arrival.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;

}
-2

Source: https://habr.com/ru/post/1678748/


All Articles