How to prevent YouTube js calls from slowing down page load

别来无恙 提交于 2020-01-03 07:13:22

问题


I am using https://gtmetrix.com to diagnose issues with my page speed.

The page in question has one embedded YouTube video and GTMetrix is saying that this video's JS calls are slowing down page load speed.

This is the call being made:

<iframe width="640" height="360" src="https://www.youtube.com/embed/PgcokT0AWHo" frameborder="0" allowfullscreen></iframe>

回答1:


EDIT: as of October 2019, this is not working anymore (Thanks to @CpnCrunch for the update). For the cases where it's not impacting the user experience, you can apparently add a 1000ms timeout after the page load for it to take effect.

This is an example of attibuting the src dynamically on page load, using a pure JS solution. Using event listeners instead of window.onload because with the latter, only one event can be set and it would override any precedent window.onload event:

<iframe id="videoFrame" width="640" height="360" src="" frameborder="0" allowfullscreen></iframe>
<script>
function setVideoFrame(){
  document.getElementById('videoFrame').src = 'http://example.com/';
}
if (window.addEventListener)  // W3C DOM
  window.addEventListener('load', setVideoFrame, false);
else if (window.attachEvent) { // IE DOM
  window.attachEvent('onload', setVideoFrame);
}else{ //NO SUPPORT, lauching right now
  setVideoFrame();
}
</script>

Note that the script can be anywhere in the code, but in case of no support for event listeners (which is highly unlikely with nowadays browsers), the function is launched right away, so it should be at least after the iframe element.




回答2:


I was having the same problem for a website I was doing and I stumbled upon this link How to "Lazy Load" embedded youtube videos

What it essentially does is, upon page load, it'll show a fake youtube player section (made out of css and your video image thumbnail) on the webpage and when the user clicks on it, it'll replace that fake player section with the Iframe and that's when the player will be loaded.

Code from the website

(function() {

  // get's all video wrapper divs
  var youtube = document.querySelectorAll(".youtube");

  // iterates through all the divs
  for (var i = 0; i < youtube.length; i++) {

    /* 
    gets the video id we mentioned in the data-embed attribute
    to generate image thumbnail urls, youtube has several
    resolutions.
    - mqdefault 320 x 180
    - hqdefault 480 x 360
    - sddefault - 640 x 480
    - maxresdefault - 1920 x 1080
    */
    var source = "https://img.youtube.com/vi/" + youtube[i].dataset.embed + "/sddefault.jpg";

    /*
    creates new image and sets the source attribute to the thumbnail
    url we generated above and sets it to load the image on page load
    */
    var image = new Image();
    image.src = source;
    image.addEventListener("load", function() {
      youtube[i].appendChild(image);
    }(i));

    /*
    below is where the magic happens, we attach click listeners to the 
    video embed divs and when clicked we create a new iframe and sets
    it inside the video wrapper div and only then will the js files
    associated with the embedded video be loaded
    */

    youtube[i].addEventListener("click", function() {

      var iframe = document.createElement("iframe");

      iframe.setAttribute("frameborder", "0");
      iframe.setAttribute("allowfullscreen", "");
      iframe.setAttribute("src", "https://www.youtube.com/embed/" + this.dataset.embed + "?rel=0&showinfo=0&autoplay=1");

      this.innerHTML = "";
      this.appendChild(iframe);
    });
  };

})();
html {
  background-color: #f3f3f3;
}

.wrapper {
  max-width: 680px;
  margin: 60px auto;
  padding: 0 20px;
}

.youtube {
  background-color: #000;
  margin-bottom: 30px;
  position: relative;
  padding-top: 56.25%;
  overflow: hidden;
  cursor: pointer;
}

.youtube img {
  width: 100%;
  top: -16.82%;
  left: 0;
  opacity: 0.7;
}

.youtube .play-button {
  width: 90px;
  height: 60px;
  background-color: #333;
  box-shadow: 0 0 30px rgba( 0, 0, 0, 0.6);
  z-index: 1;
  opacity: 0.8;
  border-radius: 6px;
}

.youtube .play-button:before {
  content: "";
  border-style: solid;
  border-width: 15px 0 15px 26.0px;
  border-color: transparent transparent transparent #fff;
}

.youtube img,
.youtube .play-button {
  cursor: pointer;
}

.youtube img,
.youtube iframe,
.youtube .play-button,
.youtube .play-button:before {
  position: absolute;
}

.youtube .play-button,
.youtube .play-button:before {
  top: 50%;
  left: 50%;
  transform: translate3d( -50%, -50%, 0);
}

.youtube iframe {
  height: 100%;
  width: 100%;
  top: 0;
  left: 0;
}
<!-- (1) video wrapper,  data-embed contains ID of the Youtube video-->
<div class="youtube" data-embed="AqcjdkPMPJA">

  <!-- (2) the "play" button -->
  <div class="play-button"></div>

</div>



回答3:


Look at given examples of using an iframe with src attribute and with dynamic src attribute with GTMatrix results.

<html>
<head>
    <title>-</title>
</head>
<body>
    <iframe id="myvideo" width="640" height="360" src="https://www.youtube.com/embed/PgcokT0AWHo" frameborder="0" allowfullscreen></iframe>
</body>
</html>

Here is the result of GTMatrix for above code.

Now check dynamic src code.

<html>
<head>
    <title>-</title>
    <script type="text/javascript">
        function test()
        {
            document.getElementById('myvideo').src = 'https://www.youtube.com/embed/PgcokT0AWHo';
        }
    </script>
</head>
<body onload="test();">
    <iframe id="myvideo" width="640" height="360" frameborder="0" allowfullscreen></iframe>
</body>
</html>

Now, look at the GTMatrix result after applying dynamic src to the iframe.

Hope these examples will help you to evaluate your problem.




回答4:


One possible approach is to not use the iframe directly but add it on some event listener, like click.

Have a look at this solution which I've been using on my website since long time (shameless promotion - Demo)

Here I show a preview image with a play button. When user clicks the image, the YouTube iframe is dynamically added to page, saving tons on bytes on page load. The code below is almost production ready and can be used as per your requirements.

if (document.querySelector("#videoPlayer")) {
  document.querySelector("#videoPlayer a").addEventListener("click", playVideo);
}
function playVideo() {
  var player = document.getElementById("videoPlayer");
  var id = player.getAttribute("data-id");
  player.classList.add("loaded");
  var src =
    "https://www.youtube.com/embed/" +
    id +
    "?autoplay=1&autohide=1&rel=0&modestbranding=1&showinfo=0&border=0&wmode=opaque&theme=light&iv_load_policy=3";
  var iframe =
    "<iframe width='100%' height='100%' src='" +
    src +
    "' scrolling='no frameborder='0' allowfullscreen></iframe>";
  player.innerHTML = iframe;
  return false;
}
#videoPlayer {
  background-color: #000;
  max-width: 100%;
  overflow: hidden;
  position: relative;
  cursor: pointer;
  height: 380px;
  width: 100%;
  margin: 1em auto;
}
#videoPlayer:after {
  content: attr(data-title);
  position: absolute;
  bottom: 0;
  left: 0;
  display: block;
  background: rgba(0, 0, 0, 0.5);
  width: 100%;
  max-height: 100px;
  text-align: left;
  padding: 1em;
  font-size: 1.2em;
  color: #fff;
  transition: opacity 0.7s ease-in-out;
}
#videoPlayer:hover:after {
  opacity: 0;
}
#videoPlayer .thumb {
  bottom: 0;
  display: block;
  left: 0;
  margin: auto;
  max-width: 100%;
  position: absolute;
  right: 0;
  top: 0;
  width: 100%;
  height: auto;
  opacity: 0.8;
  filter: alpha(opacity=80);
  transition: all 200ms ease-out;
  -webkit-transition: all 200ms ease-out;
}
#videoPlayer .thumb:hover {
  -webkit-transform: scale(1.2);
  transform: scale(1.2);
}
#videoPlayer .play {
  filter: alpha(opacity=90);
  opacity: 0.9;
  height: 97px;
  left: 50%;
  margin-left: -38px;
  margin-top: -38px;
  position: absolute;
  top: 50%;
  width: 136px;
  background: url("http://i.imgur.com/TxzC70f.png");
  background-repeat: no-repeat;
}
#videoPlayer.loaded:after {
  display: none;
}
<div id="videoPlayer" data-title="NBA 2K18 - Get Shook Trailer" data-id="lwBqitrE3ww"> <a title="Click to play video : NBA 2K18 - Get Shook Trailer"> <img class="thumb" alt="NBA 2K18 - Get Shook Trailer" src="https://1.bp.blogspot.com/-X4naiytBpyU/WZRt5d3P1iI/AAAAAAAADq8/y4IAHBmh39kqdwu8THECuObG3r9HIfa9wCLcBGAs/s800/nba-2k18-get-shook-trailer-hoopsvilla.jpg" /><span class="play"></span></a></div> 
</div>

Note: The demo above may not work due to cross-origin cookie issues. Please see the demo on codepen.

Possible improvements:

  1. Support multiple videos on same page. It currently allows only one video. It can be done easily with class based selectors.



回答5:


You could replace:

<iframe src="https://www.youtube.com/embed/LcIytqkbdlo" height="180" width="320"></iframe>

with

<div class="youtube" id="LcIytqkbdlo" style="width: 320px; height: 180px;"></div> <script src="https://labnol.googlecode.com/files/youtube.js"></script>

as exemplified here: https://www.mainstreethost.com/blog/light-youtube-embeds-faster-page-load/

You could find another useful article which addresses your problem over here: https://mikeindustries.com/blog/archive/2007/06/widget-deployment-with-wedje

WEDJE creates a cross-platform, cross-browser defer by using the document object model (DOM) to append a div, create a script element, and then append the script element to the div, all with JavaScript. An example of the technique follows:

<script type="text/javascript"> // create div below
(function( ){document.write('<div id="wedje_div_example">Loading widget...<\/div>');
    s=document.createElement('script'); // create script element
    s.type="text/javascript"; // assign script to script element
    s.src="http://www.example.com/scripts/widget.js";
    // assign script s to div element
    setTimeout("document.getElementById('wedje_div_example').appendChild(s)",1);})( )
</script>

When these elements are linked together in this way, browsers appear to decouple the loading and execution of the attached JavaScript, making widget execution asynchronous! Here is the matching external JavaScript file, widget.js, which grabs the div we created earlier and loads an image:

        document.getElementById('wedje_div_example').innerHTML+='<img src="https://www.example.com/images/example.gif" width="60" height="60" />';



回答6:


<iframe width="640" height="360" src="" data-src="https://www.youtube.com/embed/PgcokT0AWHo" frameborder="0" allowfullscreen></iframe>

<script>
function init() {
    var vidDefer = document.getElementsByTagName('iframe');
    for (var i=0; i<vidDefer.length; i++) {
        if(vidDefer[i].getAttribute('data-src')) {
            vidDefer[i].setAttribute('src',vidDefer[i].getAttribute('data-src'));
        } 
    } 
}
window.onload = init;
</script> 



回答7:


I couldn't find any workable solutions, so I wrote a javascript library to do this:

https://github.com/groupboard/ytdefer

It initially displays an image, and when the user clicks on it it then uses the YouTube Iframe API to load the video, and then start playing it (so that two clicks aren't required).



来源:https://stackoverflow.com/questions/50410828/how-to-prevent-youtube-js-calls-from-slowing-down-page-load

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!