1

Currently I am doing the below but bogging down the call-stack; how could I use perhaps an async await or newer promise functions to handle this better? I have a dynamic node that is added to the dom at different times due to various load times - instead of checking over and over again with something like the below, could I simply handle with an async await somehow?

function checkForNode() { 
    let coolNode= document.getElementById("CoolDomNode");
    if (coolNode) {
        doManyThings(coolNode);
    } else { 
        checkForNode()
    }
}
Armen Michaeli
  • 8,625
  • 8
  • 58
  • 95
Dr Upvote
  • 8,023
  • 24
  • 91
  • 204
  • 1
    Is `CoolDomNode` something you insert in your DOM later? – AKT Jun 26 '20 at 16:20
  • Modelling UI like this is tough times. [Observables](https://rxjs-dev.firebaseapp.com/guide/observable) might feel more natural for you. – richytong Jun 26 '20 at 16:24
  • I dont think if async/await will work there. You may be able to use MutationObserver to keep track of dom changes then, trigger your function appropriately. Here is a SO [answer](https://stackoverflow.com/questions/2844565/is-there-a-javascript-jquery-dom-change-listener) – dabishan Jun 26 '20 at 16:27
  • You can't wait for a node like that, Doc -- `checkForNode` will flood the call stack, and won't give the parser chance to continue parsing the document text and adding nodes to it. The parser runs *between* script invocations, there is no concurrency or parallelism, otherwise you'd have a much more complex runtime environment -- one node during one loop iteration, and two the next iteration and so on. So to drive the point home -- you can't recursively wait for a node -- you need to yield control and let the parser run at least once, then try again. Which would be very inefficient, by the way. – Armen Michaeli Jun 26 '20 at 16:42

2 Answers2

0

This is not an asynchronous job so async/await won't fix the problem. Instead you can use seTimeout so that the recursion won't happen on the same stack. With setTimeout you can also set a delay between each iteration to lower CPU usage, like so:

checkForNode() { 
  let coolNode = document.getElementById("CoolDomNode");

  if (coolNode) {
    doManyThings(coolNode);
  } else { 
    setTimeout(checkForNode, 500);  // if you want this to run as often as possible then set the delay to 0
  }
}

BTW, what you are doing is a perfect job for MutationObserver. MutationObserver notifies you when changes to the DOM tree happens. You can specify a root element, and when a new element gets added as a descendant of your root element a callback will be called:

var observer = new MutationObserver(function(mutations) {             // when mutations happen
  mutations.forEach(function(mutation) {                              // for each mutation
    mutation.addedNodes.forEach(function(addedNode) {                 // check every added node in that mutation
      if(addedNode.id === "CoolDomNode") {                            // if it's the node you're looking for
        doManyThings(addedNode);                                      // do your thing
      }
    });
  });
});

observer.observe(document.body, { childList: true, subtree: true });  // observe any changes in the body and its entire subtree. You can narrow down the subtree for optimal performance
ibrahim mahrir
  • 31,174
  • 5
  • 48
  • 73
0

Since a MutationObserver-based solution has been covered -- and it certainly is normally the way to go with these kind of things -- I want to mention an "older" way that may or may not always be applicable.

It is based on the fact that preceding nodes are available to a script before successive nodes, and you can thus place a script after the node (or inside it) to access the node and (when placed after) its contents:

<div id="CoolDomNode">Hello</div>
<script>
    document.getElementById("CoolDomNode");
    /// or
    document.currentScript.previousElementSibling;
</script>

I'll let you assess yourself which of the solutions fits you better and why. In brief, observing the document for changes has linear cost increase with the number of nodes in the document, which may outweigh the benefit of waiting for just that one node. Placing a script after node of interest, however, is more of a pollution to the hypertext, one may argue, and obviously depends on the node being part of the document in the first place.

Armen Michaeli
  • 8,625
  • 8
  • 58
  • 95