图像和按钮不会每次都加载

时间:2012-03-05 00:09:28

标签: javascript

我是JavaScript新手。我创建了下面链接的网页作为我正在上课的练习。

JavaScript Product Catalog

如果它们都正确加载似乎工作正常,但有一半时间图像或按钮没有加载,有时缩略图加载但不加载全尺寸(鼠标悬停)图像。在Firefox或IE中,它似乎只发生在第一次加载时,之后(只要浏览器保持打开状态),它就会在每次加载后成功加载。但在Chrome中,每个页面重新加载时它会继续随机行动。只需连续刷新页面10次,您可能会看到一些情况,其中按钮或图像(或两者)都没有加载。

我假设这是我的代码的问题,因为我从未遇到过服务器的任何其他问题。有什么想法吗?

谢谢!

<!DOCTYPE html>

<html>
<head>
   <meta charset = "utf-8">
   <style type = "text/css">
      .box { border: 1px solid black; padding: 4px }
   </style>
   <title>Product Catalog</title>
   <script>

   var catalogDiv;
   var summaryRequest;
   var descriptionsRequest;
   var thumbsRequest;
   var imagesRequest;

   function showLargeImage( imageElement )
   {
       imageElement.style.display = "none";
       imageElement.nextSibling.style.display = "inline";
   }

   function showThumb( imageElement )
   {
       imageElement.style.display = "none";
       imageElement.previousSibling.style.display = "inline";
   }

   function showDesc( descButton )
   {
      if ( descButton.nextSibling.style.display == "none" ) {
         descButton.nextSibling.style.display = "block";
      } else {
         descButton.nextSibling.style.display = "none";
      }
   }

   function getDescriptions()
   {
      try
      {
         descriptionsRequest = new XMLHttpRequest();
         descriptionsRequest.addEventListener("readystatechange",
            loadDescriptions, false );
         descriptionsRequest.open( "GET", "descriptions.json", true );
         descriptionsRequest.setRequestHeader( "Accept",
            "application/json; charset=utf-8" );
         descriptionsRequest.send();
      }
      catch ( exception )
      {
         alert( "Request Failed" );
      }
   }

   function loadDescriptions()
   {
      if ( descriptionsRequest.readyState == 4
         && descriptionsRequest.status == 200 )
      {
         var descriptions = JSON.parse( descriptionsRequest.responseText );
         for ( var i = 0; i < descriptions.length; i++ ) {
            var infoDiv = document.getElementById( descriptions[i].id +
               "-info-inner" );

            var descButton = document.createElement( "button" );
            infoDiv.appendChild( descButton );
            descButton.type = "button";
            descButton.textContent = "show description";
            descButton.setAttribute( "onclick", "showDesc( this )");

            var desc = document.createElement( "fieldset" );
            desc.style.display = "none";
            desc.style.margin = "10px";
            infoDiv.appendChild( desc );
            desc.innerHTML = "<br>" + descriptions[i].text + "<br><br>" ;
         }
      }
   }

   function getImages()
   {
      try
      {
         imagesRequest = new XMLHttpRequest();
         imagesRequest.addEventListener("readystatechange",
            loadImages, false );
         imagesRequest.open( "GET", "images.json", true );
         imagesRequest.setRequestHeader( "Accept",
            "application/json; charset=utf-8" );
         imagesRequest.send();
      }
      catch ( exception )
      {
         alert( "Request Failed" );
      }
   }

   function loadImages()
   {
      if ( imagesRequest.readyState == 4 && imagesRequest.status == 200 )
      {
         var images = JSON.parse( imagesRequest.responseText );
         for ( var i = 0; i < images.length; i++ ) {
            var imageDiv = document.getElementById( images[i].id +
               "-image-inner" );
            imageDiv.innerHTML += "<img style=\"display:none;\"" +
               "src=\"" + images[i].filename+ "\">";
            imageDiv.lastChild.setAttribute( "onmouseout",
               "showThumb( this )" );
         }
      }
   }   

   function getThumbs()
   {
      try
      {
         thumbsRequest = new XMLHttpRequest();
         thumbsRequest.addEventListener("readystatechange",
            loadThumbs, false );
         thumbsRequest.open( "GET", "thumbs.json", true );
         thumbsRequest.setRequestHeader( "Accept",
            "application/json; charset=utf-8" );
         thumbsRequest.send();
      }
      catch ( exception )
      {
         alert( "Request Failed" );
      }
   }

   function loadThumbs()
   {
      if ( thumbsRequest.readyState == 4 && thumbsRequest.status == 200 )
      {
         var thumbs = JSON.parse( thumbsRequest.responseText );
         for ( var i = 0; i < thumbs.length; i++ ) {
            var imageDiv = document.getElementById( thumbs[i].id +
               "-image-inner" );
            imageDiv.innerHTML = "<img style=\"display:inline;\"" +
               "src=\"" + thumbs[i].filename+ "\">";
            imageDiv.firstChild.setAttribute( "onmouseover",
               "showLargeImage( this )");
         }
      }
   }   

   function setupDivsRequest()
   {
      try
      {
         summaryRequest = new XMLHttpRequest();
         summaryRequest.addEventListener("readystatechange",
            setupDivsResponse, false );
         summaryRequest.open( "GET", "summary.json", true );
         summaryRequest.setRequestHeader( "Accept",
            "application/json; charset=utf-8" );
         summaryRequest.send();
      }
      catch ( exception )
      {
         alert( "Request Failed" );
      }
   }

   function setupDivsResponse()
   {
      if ( summaryRequest.readyState == 4 && summaryRequest.status == 200 )
      {
         var summary = JSON.parse( summaryRequest.responseText );

         for ( var i = 0; i < summary.length; i++ ) {

            var productDiv = document.createElement( "div" );
            var productImageOuterDiv = document.createElement( "div" );
            var productImageInnerDiv = document.createElement( "div" );
            var productInfoOuterDiv = document.createElement( "div" );
            var productInfoInnerDiv = document.createElement( "div" );

            catalogDiv.appendChild(productDiv);
            productDiv.appendChild( productImageOuterDiv );
            productDiv.appendChild( productInfoOuterDiv );
            productImageOuterDiv.appendChild( productImageInnerDiv );
            productInfoOuterDiv.appendChild( productInfoInnerDiv );

            productDiv.id = summary[i].id;
            productDiv.className = "box";

            productImageOuterDiv.id = summary[i].id + "-image-outer";
            productImageOuterDiv.style.cssFloat = "left";

            productImageInnerDiv.id = summary[i].id + "-image-inner";
            productImageInnerDiv.style.height = "250px";
            productImageInnerDiv.style.width = "250px";
            productImageInnerDiv.style.display = "table-cell";
            productImageInnerDiv.style.verticalAlign = "middle";
            productImageInnerDiv.style.textAlign = "center";

            productInfoOuterDiv.id = summary[i].id + "-info-outer";
            productInfoOuterDiv.style.height = "250px";

            productInfoInnerDiv.id = summary[i].id + "-info-inner";
            productInfoInnerDiv.style.float = "left";
            productInfoInnerDiv.style.padding = "10px";

            productInfoInnerDiv.innerHTML = summary[i].title + "<br>";
            productInfoInnerDiv.innerHTML += summary[i].price + "<br><br>";
         }
      }
   }   

   function start()
   {
      catalogDiv = document.getElementById( "catalog" );
      setupDivsRequest();
      getThumbs();
      getImages();
      getDescriptions();
   }

   window.addEventListener( "load", start, false );
   </script>
</head>
<body>
   <h1>Mouse over a product thumbnail for a larger picture.</h1>
   <div id = "catalog"></div>
</body>
</html>

1 个答案:

答案 0 :(得分:0)

花了很长时间,但我终于找到了这个问题的底部。这是填充相同元素的多个异步请求之间的竞争条件。我没有想过这是可能的,所以我期望先去的那个会将第一个HTML添加到元素中:

element.innerHTML = "first text";

虽然我希望第二个请求添加第二个HTML:

element.innerHTML += "second text";

显然,如果这些请求出现故障,由于我使用=+=的方式,结果将是“第二个文本”被覆盖,这就是为什么我的图像不是'加载一半的时间。 (即使我在两种情况下都使用了+=,我仍然会遇到随机排序元素的问题,如下面的代码所示。)

无论出于何种原因,在Firefox或IE中,竞争条件似乎都不重要。也许这些浏览器中的某些东西试图通过强制请求按照它们开始的顺序完成来防范这种情况?或许这只是运气不好。但在Chrome中,请求会以随机顺序一致完成。下面简单的代码清楚地说明了这一点。在Chrome中,有一半的时间你会得到“FOOBAR”作为HTML输出,但另一半时间你会得到“BARFOO”。我在脚本中引用的testx.json文件是虚拟(空)文件。

在这种情况下,通过在完成其他任务后让第一个设置的回调函数调用我的第二个设置功能,可以很容易地解决竞争条件。在一个更复杂的情况下,我猜其他典型的竞争条件保障(互斥和信号量)也会起作用。

<!DOCTYPE html>

<html>
<head>
   <script>

   var testDiv;
   var request1;
   var request2;

   window.addEventListener( "load", start, false );

   function start()
   {
      testDiv = document.getElementById( "test-div" );
      setup1();
      setup2();
   }

   function setup1()
   {
      try
      {
         request1 = new XMLHttpRequest();
         request1.addEventListener("readystatechange",
            response1, false );
         request1.open( "GET", "test1.json", true );
         request1.setRequestHeader( "Accept",
            "application/json; charset=utf-8" );
         request1.send();
      }
      catch ( exception )
      {
         alert( "Request Failed" );
      }
   }

   function response1()
   {
      if ( request1.readyState == 4 && request1.status == 200 )
      {
         testDiv.innerHTML += "FOO";
      }
   } 

   function setup2()
   {
      try
      {
         request2 = new XMLHttpRequest();
         request2.addEventListener("readystatechange",
            response2, false );
         request2.open( "GET", "test2.json", true );
         request2.setRequestHeader( "Accept",
            "application/json; charset=utf-8" );
         request2.send();
      }
      catch ( exception )
      {
         alert( "Request Failed" );
      }
   }

   function response2()
   {
      if ( request2.readyState == 4 && request2.status == 200 )
      {
         testDiv.innerHTML += "BAR";
      }
   }   

   </script>
</head>
<body>
   <div id = "test-div"> </div>
</body>
</html>