2017-02-13 2 views
-3

Lösung: Es scheint ein Problem in der Art, wie ich meinen Warteschlangenmechanismus in window.onload aufgerufen habe.Javascript-Funktionsaufruf schlägt fehl in Kopf, aber nicht in Körper

Präambel - ich bin froh, dass ich zu sehen bin als Duplikat markiert werden, wo die Lösung zu verwenden window.onload ist, das ist etwas, das ich schon hier bin mit. Ein paar Kommentare haben gezeigt, mögliche Probleme mit der Warteschlange, die ich von einer anderen Stackoverflow-Lösung erhielt, aber mich im Dunkel lassen wegen des Mangels an Ausarbeitung.

Frage: Wenn ich einen Funktionsaufruf im Kopf zu machen, scheitert es. Wenn ich einen Funktionsaufruf im Körper mache, ist es erfolgreich. Warum?

Erweiterung: Warum in global.js die Anrufe auf die gleiche Funktion haben, die über dem andernfalls Anruf ist, gelingen?

Ich habe einige Javascript, das eine onload "queue" verstimmt (Funktion addLoadEvent in global.js) schafft. Ein Aufruf dieser Funktion fügt die Warteschlange hinzu, wenn onload aufgerufen wird.

Außer, ich habe festgestellt, dass eine bestimmte Skriptfunktion Anruf fehlschlägt, wenn es im Kopf vs im Körper befindet. Ich kann nicht herausfinden, warum, weil alles, was benötigt wird (andere js-Funktionen) über den Funktionsaufruf selbst geladen werden, und der eigentliche Aufruf der Funktion wird nicht bis onload ausgelöst, um sicherzustellen, dass die notwendigen HTML-Elemente vorhanden sind.

Reihenfolge der Beladung:

  1. html
  2. global.js to head-Datei - darunter addLoadEvent (func)
    • addLoadEvent x2 (erfolgreich)
  3. Inline-Skript in Kopf - umfasst initialFighter()
    • addLoadEvent (Standort ein - nicht)
  4. HTML-Datei nach dem Kopf
    • addLoadEvent (Standort zwei - gelingt)
  5. onload löst Warteschlange Anrufe

Für die Zwecke Diese Frage, der Funktionsaufruf, der aufgrund seines Standorts fehlschlägt oder erfolgreich ist, ist der folgende.

addLoadEvent(initialFighter()); 

Hier ist die abgespeckte HTML, beachten Sie die 2 Standorte markiert. Wenn ich den obigen Funktionsaufruf an Position eins kopiere, schlägt er fehl. Wenn ich den obigen Funktionsaufruf an Position zwei kopiere, ist es erfolgreich.

<!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> 

Im Folgenden finden Sie global.js, die das erste Skript-Datei geladen ist:

Beachten Sie, dass es 2 addLoadEvent sind (funk) hier nennt, und sie Erfolg haben (nicht laufen erst nach HTML-Elemente existieren), obwohl sie über allem anderen stehen.

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

'addLoadEvent (loadFile ('nav', 'nav.txt'));' tut nicht, was Sie denken, dass es tut. – zzzzBov

+0

Das Argument zu 'addLoadEvent' muss eine Funktion sein, kein Aufruf einer Funktion. – Barmar

+0

Können Sie bitte diese Kommentare klären? Wenn es nicht tut, was es zu tun scheint, wie funktioniert es immer noch an den meisten Orten? Barnar, Sie geben an, dass ich falsche Parameter an addLoadEvent sende, aber irgendwie funktioniert es immer noch in den meisten Fällen? Wenn die Parameter vom falschen Typ wären, würde es nicht zu 100% ausfallen? – Doug

Antwort

1

Das Argument addLoadEvent soll eine Funktion sein, die während der onload Rückruf aufgerufen wird. Sie rufen die Funktion sofort auf und übergeben ihren Rückgabewert, sodass die Funktion nicht auf das Ereignis onload wartet, und Sie erhalten Fehler, weil die Elemente noch nicht im DOM enthalten sind. Es sollte sein:

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

Sie keine anonyme Wrapper-Funktion für initialFighter müssen, da es keine Argumente nehmen. Sie müssen nur die () weglassen, so dass Sie einen Verweis auf die Funktion übergeben, anstatt die Funktion sofort aufzurufen.

Auch anstelle von Verkettungs onload Event-Handler durch den alten Wert zu speichern und es in der neuen Funktion aufrufen, können Sie einfach addEventListener verwenden, da diese automatisch in die Liste der Listener hinzufügen anstatt sie zu ersetzen:

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

interessant. Die Erklärung macht Sinn, und ich werde versuchen, es zu implementieren, aber ich kann immer noch nicht richtig herausfinden, wie diese 2 loadFile-Aufrufe funktionierten, wenn sie nicht in die Warteschlange gestellt wurden. Wenn sie nicht in die Warteschlange gestellt wurden, geschahen diese Anrufe eindeutig vor der Existenz der Elemente, die sie modifizieren sollten, was sie ebenfalls zum Scheitern gebracht haben sollte. Hoppla! Editieren, für Antwort Teil 2 muss ich in addEventListener schauen, ich bin nicht vertraut mit dem, wie das in window.onload funktioniert. – Doug

+0

Wenn Sie es an Position zwei setzen, sollte 'loadFile ('nav', 'nav.txt')' funktionieren, aber 'loadFile ('footer', 'footer.txt')' sollte fehlschlagen, weil Position zwei nach der 'nav' Element ist geladen. Der Aufruf von 'loadFile' wird nicht in die Warteschlange gestellt, dies geschieht sofort. – Barmar

+0

'initialFighter()' arbeitet im Körper, weil es nach dem 'Bild' Element geladen ist. – Barmar

Verwandte Themen