Javascript函数调用在头部失败,但在体内失败

时间:2017-02-13 23:15:23

标签: javascript html onload head

解决方案:我将排队机制调用到window.onload的方式似乎存在问题。

序言 - 我很高兴看到我被标记为副本,解决方案是使用window.onload,这是我已经在这里使用的东西。一些评论表明我从另一个stackoverflow解决方案中获得的队列可能存在问题,但由于缺乏详细说明而让我陷入困境。

问题:如果我在头部进行函数调用,则会失败。如果我在体内进行函数调用,它就会成功。为什么呢?

扩展:为什么在失败调用之上的global.js中对同一函数的调用成功?

我有一些javascript可以创建一个onload" queue"排序(global.js中的函数addLoadEvent)。对此函数的调用会在调用onload时添加到队列中。

除此之外,我发现如果特定的脚本函数调用位于头部和体内,则会失败。我无法弄清楚为什么,因为所需的一切(其他js函数)都被加载到函数调用本身之上,并且在onload之前不会触发对函数的实际调用,从而确保存在必要的html元素。

装载顺序:

  1. html文件到头
  2. global.js - 包括addLoadEvent(func)
    • addLoadEvent x2(成功)
  3. 内联脚本 - 包括initialFighter()
    • addLoadEvent(位置一 - 失败)
  4. html文件后头
    • addLoadEvent(位置二 - 成功)
  5. onload触发排队呼叫
  6. 出于这个问题的目的,基于它的位置失败或成功的函数调用如下。

    addLoadEvent(initialFighter());
    

    这里是精简的HTML,请注意标记的2个位置。如果我将上述函数调用复制粘贴到位置1,则失败。如果我将上述函数调用复制粘贴到位置二,则成功。

    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="utf-8" />
      <script src="global.js"></script>  
      <script type="text/javascript">
      function showFighter(id) {
        var pic = document.getElementById("picture");
        var picPath = 'url(images/' + id + '.png)';
        pic.style.backgroundImage = (picPath);
      }
      function initialFighter() {
        var fighter = getURLParameter('fighter');
        if (typeof(fighter) != "undefined" && fighter != null) {
          showFighter(fighter);
        } else {
          showFighter('Foobar');
        }
      }
      ***** LOCATION ONE *****
      </script>
    </head>
    <body>
    <header></header>
    <nav id="nav"></nav>
    <section id="fighters">
      <div id="picture"></div>
      <div id="text"></div>
      <script type="text/javascript">
      ***** LOCATION TWO *****
      </script>
    </section>
    <footer id="footer"></footer>
    </body>
    </html>
    

    下面是global.js,这是第一个加载的脚本文件:

    请注意,这里有2个addLoadEvent(func)调用,并且它们成功(直到html元素存在之后才会运行),尽管几乎所有其他内容都是如此。

    function addLoadEvent(func) {
      var prevOnLoad = window.onload;
      if (typeof window.onload != 'function') {
        window.onload = func;
      } else {
        window.onload = function() {
          if (prevOnLoad) {
            prevOnLoad();
          }
          func();
        }
      }
    }
    
    function loadFile(id, filename) {
      var xmlhttp;
      if (window.XMLHttpRequest) {
        xmlhttp=new XMLHttpRequest();
      }
      xmlhttp.onreadystatechange=function() {
        if (xmlhttp.readyState==4 && xmlhttp.status==200) {
          document.getElementById(id).innerHTML=xmlhttp.responseText;
        }
      }
      xmlhttp.open('GET', filename, true);
      xmlhttp.send();
    }
    
    addLoadEvent(loadFile('nav', 'nav.txt'));
    addLoadEvent(loadFile('footer', 'footer.txt'));
    
    function getURLParameter(name) {
      return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search) || [null, ''])[1].replace(/\+/g, '%20')) || null;
    }
    

1 个答案:

答案 0 :(得分:1)

addLoadEvent的参数应该是一个函数,它将在onload回调期间调用。您立即调用该函数并传递其返回值,因此该函数不会等待onload事件,并且您会收到错误,因为DOM中的元素尚未生效。它应该是:

addLoadEvent(function() { loadFile('nav', 'nav.txt'); });
addLoadEvent(function() { loadFile('footer', 'footer.txt'); });
addLoadEvent(initialFighter);

您不需要initialFighter的匿名包装函数,因为它不会接受任何参数。你只需要省略(),所以你传递了对函数的引用,而不是立即调用函数。

此外,通过保存旧值并在新函数中调用它来代替链接onload事件处理程序,您可以简单地使用addEventListener,因为它们会自动添加到侦听器列表而不是替换它:

function addLoadEvent(func) {
  window.addEventListener("load", func);
}