Search code examples
javascripthtml5-audiointersection-observer

Inserting an intesection observer in the right place in order to avoid an enormous network payload


I have an mp3 from an external URL via <audio></audio> tag. As on mobile it takes a few seconds to download before being ready to play, I've added a spinner which reveals the player only once the mp3 is ready to play - so nobody is going to click on play if there's no sound yet.

Everything works, except an ENORMOUS NETWORK PAYLOAD, as the page finish to load only when the first bytes of the mp3 are dowloaded and therefore is ready to play (the mp3 comes in ranges of data - partial content code 206).

So, to avoid the ENORMOUS NETWORK PAYLOAD, I'm thinking to lazy load the mp3, or maybe the whole player, using intersection observer, as the mp3 audio tag is below the fold. But then the mp3 is not downloaded at all.

I've placed the intersection observer after the audio tag is revealed (after the loading spinner is gone), but the mp3 is not downloaded. I've tried everything everywhere, but no success.

I just started to learn some javascript, and I'm not even sure if using the intersectin observer to load the page first, and then the mp3, is a good idea in this case. And anyway I can't make it work, so any help or suggestion is much appreciated. Thank you.

Here's the code:

  <div class="player">

    <div class="hide animated" id="player">  {# spinner #}

      <audio data-src="https://some.com/track.mp3"></audio>

    </div> {# spinner #}

      <div class="circle-spin" id="loaderSpinner" role="status"></div> {# spinner #}

   </div>

--

// SPINNER
window.addEventListener("load", function(){
  document.getElementById("loaderSpinner").style.display = "none";
  document.getElementById("player").classList.remove('hide');
  });


// On the document's DOMContentLoaded event, this script should queries the DOM for audio tag -- so, I guess
document.addEventListener("DOMContentLoaded", function() {

  const mp3 = document.querySelector('audio');

  const io = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
      if (!entry.isIntersecting) return;
      entry.target.src = entry.target.getAttribute('data-src');
      io.unobserve(entry.target);
    })
  });

  io.observe(mp3);

});

 
// And here's some customization for audio player controls which starts with load sound via <audio tag
const audioElement = document.querySelector("audio");
const audioCtx = new AudioContext();
const track = audioCtx.createMediaElementSource(audioElement);

// follows Player controls and attributes...

// and finally an event listener that waits for the page to load etc etc
window.addEventListener("load", () => {
  // Set times after page load
  setTimes();
// etc etc etc...

Solution

  • I think the problem comes from the fact that your observer will never trigger because your audio has no source.

    The audio tag is not even added to the DOM if there is no valid src from the tests I quickly ran.

    Also, what you are trying to achieve is already baked in the audio tag. You can use the preload attribute to tell the browser if/how it should preload the audio stream.

    Values can be:

    auto The author thinks that the browser should load the entire audio file when the page loads

    metadata The author thinks that the browser should load only metadata when the page loads

    none The author thinks that the browser should NOT load the audio file when the page loads

    So, for you, I think you'd like none or metadata.

    Parts of the answer come from W3CSchools