title: MutationObserver callback only when all resources have loaded
body: <h2>Requirement</h2>
  
  <p>I need to dynamically update the content of an element, and then perform an animation once the element and its content are loaded. In this particular case the element has an opacity of 0, and once the content is loaded I set its opacity to 1 with a CSS transition to fade it in. The element's content has a large number of images, in both <code>&lt;img&gt;</code> tags and as <code>background-image</code>s of sub elements. It is very important that the animation is only allowed to start once all the images and background-images have loaded. Otherwise the fade-in effect is broken, as empty placeholder elements are animated in with their image content appearing an instant later, as shown below.</p>
  
  <p><a href="https://i.stack.imgur.com/bne0b.gif" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/bne0b.gif" alt="page load"></a></p>
  
  <h2>Partial Solutions</h2>
  
  <p>To determine when the element's content is loaded I am using a <code>MutationObserver</code> to observe the element and fire a callback that changes its opacity when a change is detected.</p>
  
  <pre><code>var page = document.getElementById( "page" );
  var observer = new MutationObserver( function(){
      page.style.opacity = "1"; // begin animation on change
  } );
  var config = { characterData: true,
                 attributes: false,
                 childList: false,
                 subtree: true };
  
  observer.observe( page, config );
  page.innerHTML = newContent; // update content
  </code></pre>
  
  <p>However, by itself a <code>MutationObserver</code> is not a comprehensive solution to the requirement. As the <a href="https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver/observe" rel="nofollow noreferrer">MDN</a> page states:</p>
  
  <blockquote>
    <p>The MutationObserver method observe() configures the MutationObserver callback to begin receiving notifications of changes to the DOM that match the given options.</p>
  </blockquote>
  
  <p>DOM changes fire once the subtree is modified and when all resources that would prevent the DOM from being parsed are loaded. This does not include images. Thus, <code>MutationObserver</code>s will fire the callback without regard as to whether the content's images are fully loaded.</p>
  
  <p>If I set the <code>childList</code> parameter to <code>true</code>, within the callback I could look at every child that changes and attach a <code>load</code> event listener to each <code>&lt;img&gt;</code>, keeping track of the total number that I attach. Once all the <code>load</code> events have fired I would know that every image has loaded.</p>
  
  <p><div class="snippet" data-lang="js" data-hide="true" data-console="false" data-babel="false">
  <div class="snippet-code snippet-currently-hidden">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>var page = document.getElementById( "page" ),
      total = 0,
      counter = 0;
  
  var callback = function( mutationsList, observer ){
      for( var mutation of mutationsList ) {
          if ( mutation.type == 'childList' ) {
              Array.prototype.forEach.call( mutation.target.children, function ( child ) {
                  if ( child.tagName === "IMG" ) {
                      total++; // keep track of total load events
                      child.addEventListener( 'load', function() {
                          counter++; // keep track of how many events have fired
                          if ( counter &gt;= total ) {
                              page.style.opacity = "1";
                          }
                      }, false );
                  }
              } );
          }
      }
  }
  
  var observer = new MutationObserver( callback );
  var config = { characterData: true,
                attributes: false,
                childList: true,
                subtree: true };
  
  observer.observe( page, config );
  page.innerHTML = newContent; // update content</code></pre>
  </div>
  </div>
  </p>
  
  <p>However, there are elements with background images that must also be loaded. Since <code>load</code> cannot be attached to such elements, this solution is useless when detecting if background-images have loaded.</p>
  
  <h2>Problem Statement</h2>
  
  <p>How can I use a <code>MutationObserver</code> to determine when <em>all</em> resources of a dynamically updated element are loaded? In particular, how can I use it to ascertain that implicitly dependent resources such as background images have loaded?</p>
  
  <p>If this cannot be achieved with <code>MutationObserver</code>s, how else could this be achieved? Using <code>setTimeout</code> to delay the animation is not a solution.</p>