ebody: jQuery get() - Variablen innerhalb von get() auch außerhalb nutzen

Hallo,

es ist nur ein Beispielcode der das Problem darstellen soll. Ziel ist es, Inhalte aus einer Datei in Variablen und Objekten zu speichern, um diese im Script weiter verarbeiten zu können.

var x = {};
var y = "";

$.get("datei.xml", function(data){

	$(data).find("movie").each(function(index, value){

		// Funktionen die in x und y Werte aus datei.xml speichern
	
	});

	console.log("y innerhalb: ", y);

});

console.log("x außerhalb: ", x);
console.log("y außerhalb: ", y);

$(document).ready(function() {
	
	console.log("x ready: ", x);
	console.log("y ready: ", y);

});

In der WebDev Console wird x mit Inhalt in jeder Ausgabe angezeigt. y ist immer leer nur "y innerhalb:" zeigt den Inhalt. Warum enthält y außerhalb von get() keine Werte?

Die Ausgabe in der WebDev Console hat diese Reihenfolge:

x außerhalb:{}

y außerhalb:

x ready:{}

y ready:

y innerhalb: ...Werte...

Ich dachte, evtl. ist die get() Funktion noch nicht fertig durchgelaufen und daher haben die Variablen keine Werte. Aber x hat ja Werte.

Die Reihenfolge wundert mich trotzdem etwas, denn "y innerhalb" wird erst am Ende angezeigt. Für mich sieht es so aus als wäre somit die get() Funktion auch erst später fertig und dennoch enthält x schon alle Daten.

Gruß ebody

  1. Hallo ebody,

    gemäß deines Protokolls ist x genauso leer wie y und das ist auch zu erwarten.

    Der get Request muss erstmal zurückkehren, vorher wird der Callback nicht aufgerufen.

    Die außerhalb Position wird als erstes erreicht weil das inline in Script ist. ready folgt weil das nach Fertigstellung des DOM gerufen wird.

    Irgendwann kommt get zurück und ruft den Callback. Die Reihenfolge von ready und innerhalb kann sich möglicherweise ändern wenn nach deinem Script noch externe andere Scripte geladen werden, weil der Browser darauf wartet.

    Rolf

    --
    sumpsi - posui - clusi
    1. Hi Rolf,

      x hat bei mir einen Wert. Im gesamten Code, wird x aber auch innerhalb der get() Funktion in einigen if...else Abfragen und Schleifen mit Werten befüllt, y schon vorher. Evtl. passiert es deswegen. Dennoch "entstehen" beide Variablen innerhalb von get() und x müsste ja auch leer sein.

      Ich habe jetzt diese Funktion nach und außerhalb von get() hinzugefügt.

      		getXmlValue.done(function(result) {
      		  
      		  console.log("y: ", y);
      		  
      		});
      

      Der gesamte Code:

      var x = {};
      var y = "";
      
      var getXmlValue = $.get("datei.xml", function(data){
      
      	$(data).find("movie").each(function(index, value){
      
      		// Funktionen die in x und y Werte aus datei.xml speichern
      	
      	});
      
      	console.log("y innerhalb: ", y);
      
      });
      
      getXmlValue.done(function(result) {
      		  
        console.log("y außerhalb: ", y);
      		  
      });
      

      Die WebDev Console zeigt jetzt "y außerhalb:" mit Werten. Mir ist es aber auch schon ein paar mal passiert, dass es ein Zufall oder Missverständnis war und ich "es funktioniert" falsch gedeutet habe.

      Siehst Du oder sonst jemand, dass es so wirklich funktioniert oder ob das eigentlich nicht unbedingt funktionieren müsste?

      Gruß ebody

      1. Tach!

        Siehst Du oder sonst jemand, dass es so wirklich funktioniert oder ob das eigentlich nicht unbedingt funktionieren müsste?

        Wenn der Wert garantiert erst im Callback zur Verfügung steht, musst du auch garantieren, dass erst nach Ausführung des Callbacks darauf zugegriffen wird. Das ist ein generelles Problem asynchroner Programmierung.

        dedlfix.

  2. Tach!

    es ist nur ein Beispielcode der das Problem darstellen soll. Ziel ist es, Inhalte aus einer Datei in Variablen und Objekten zu speichern, um diese im Script weiter verarbeiten zu können.

    Dein Problem, das wurde schon gesagt, ist ein reihenfolgenabhängiges. Wenn ein Vorgang das Ergebnis per Callback liefert, dann kannst du auf dieses Ergebnis immer erst nach der Ausführung des Callbacks zugreifen oder innerhalb beziehungsweise von ihm ausgehend.

    Man kann das mit Promises lösen. Wenn die Inhalte bereits da sind, ist das Promise sofort erfüllt, wenn nicht, erfüllt es sich später. Da es (vermutlich) immer nur eine Ausführung der Daten geben soll, müsste es auch noch eine Factory geben, die diese eine Promise-Instanz ausliefert, wer auch immer sie anfragt.

    Das bedeutet aber auch, dass man dazu grundlegendes Wissen im Umgang mit Promises aneignen muss.

    dedlfix.

    1. Hallo dedlfix,

      das ist bei jQuery AJAX schon drin. Man bekommt von get ein Objekt zurück, das das Promise Interface implementiert. Den Callback lässt man dann weg.

      $.get("datei.xml")
      .then(function(data) {
         // Tu was, bestimme x und y
         return {x, y};
      })
      .then(function(xy) {
         // ... Verarbeite xy.x und xy.y
      })
      .catch(function(error) {
         // ... Aua schreien
      });
      

      Die zweite Funktion bekommt ein Objekt mit den Eigenschaften x und y, wenn ich die Shortcut-Syntax richtig erinnere.

      Die erste Funktion könnte auch irgendwas tun, was ein neues Promise erzeugt, und DAS zurückgeben; die zweite Funktion würde dann beim Erfüllen des neuen Promise gerufen.

      Siehe die Doku von jQuery.ajax, dort die Erklärung zu deferred.

      Rolf

      --
      sumpsi - posui - clusi
      1. Tach!

        das ist bei jQuery AJAX schon drin. Man bekommt von get ein Objekt zurück, das das Promise Interface implementiert. Den Callback lässt man dann weg.

        Damit kommt man aber nicht besser als mit dem Callback. Das Problem an der Aufgabenstellung ist, dass der empfangene Wert global abgelegt werden soll. Wenn man ihn nur einmalig bräuchte, könnte man ihn ja im Callback oder im Promise-then behandeln und dann vergessen. Aber zum globalen Draufzugreifen möchte man nicht ständig Requests absetzen. Deswegen war mein Vorschlag, ein eigenes Promise einzusetzen, dass den Wert in einer Closure-Variable verwaltet und zurückgibt.

        dedlfix.

        1. Hallo dedlfix,

          die Frage ist doch, ob man unbedingt was Globales braucht. Jede globale Variable ist erstmal ungünstig. Und eine Ablage in einer globalen Variablen kann die 2. Funktion immer noch ausführen.

          Die Promise-Kettung sorgt dafür, dass die Verwendung der x-y Werte erst erfolgt nachdem die Rückgabe von get verarbeitet wurde.

          Rolf

          --
          sumpsi - posui - clusi
          1. Tach!

            die Frage ist doch, ob man unbedingt was Globales braucht. Jede globale Variable ist erstmal ungünstig. Und eine Ablage in einer globalen Variablen kann die 2. Funktion immer noch ausführen.

            Globale Variablen sind nicht per se ungünstig. Man vermeidet sie der möglichen Konflikte wegen, wenn sie in andere Bibliotheken gleichnamig definiert wurden. Da aber die meisten aktuellen Bibliotheken nicht im globalen Raum rumfuhrwerken, ist man da letztlich doch recht frei. Wie auch immer, ... Fortsetzung weiter unter.

            Die Promise-Kettung sorgt dafür, dass die Verwendung der x-y Werte erst erfolgt nachdem die Rückgabe von get verarbeitet wurde.

            Solange man die Kontrolle über den Ablauf hat, ist das alles kein Problem. Aber üblicherweise möchte man die wieder abgeben und erst beim nächsten userveranlassten Event wieder aufnehmen. Dann ist man aber nicht mehr in dem Kontext, in dem das Zeug liegt, das man mit dem get()/fetch/wasauchimmer holte. Deswegen ist wohl der Wunsch entstanden, die Werte global abzulegen.

            (Fortsetzung von oben)
            Global (im Sinne von Eigenschaft im window-Objekt anlegen) kann man meiden, wenn man eine IIFE anlegt, in der aller eigener Code steht. Das Problem ist aber nicht der Ort des Ablegens, sondern dass man den Zugriff auf die einmal geholten Dinge haben möchte und die dafür irgendwo global oder "global" im eigenen Scope liegen müssen. Und da macht immer noch die Asynchronität Probleme, solange man nicht kontrollieren kann, dass Zugriffe darauf entweder warten oder garantiert erst nach Eintreffen der Daten stattfinden.

            dedlfix.