JSON als globale Variable importieren

activivan

Neues Mitglied
Hallo zusammen,

ich muss eine lokale JSON Datei in JS importieren. Im Netz wird mir als Lösungsvorschlag die Fetch-API vorgeschlagen. Das Ganze klappt soweit auch ganz gut, ich kann auch die JSON Datei aus diesem Fetch Codeblock heraus console loggen.
Javascript:
fetch('stats.json')
        .then((response) => response.text())
        .then((text) => statsJson = text)
        .then(() => console.log(statsJson))
Nun will ich diese importierte JSON Datei in meinem restlichen Script als Variable verwenden. Wenn ich jedoch versuche außerhalb dieses "Fetch-Codeblocks" auf die in diesem Block definierte Variable "statsJson" zuzugreifen, wird mir angezeigt, dass diese Variable undefined ist. Wie kann ich das beheben? Oder sollte ich generell kein Fetch dazu verwenden?

Danke im Voraus!
 
Die Funktion die du suchst um aus JSON-Text ein Objekt zu machen JSON.parse():

Javascript:
var obj = JSON.parse('{"name":"Luke"}');
console.log(obj.name); // Ausgabe: Luke

Natürlich gelten die üblichen Sicherheitsbedenken, man sollte sehr sehr selten irgendwelche Strings oder Dateiinhalte direkt in Objekte parsen, und lokale Dateien eher überhaupt nicht, wenn es vermeidbar ist, und in jedem Fall a.) den Fehler abfangen, falls es kein valides JSON ist und b.) danach sorgfältig prüfen, ob es genau das richtige Objekt ist das man erwartet. Beides hab ich erstmal weg gelassen.

MfG
 
Die Funktion die du suchst um aus JSON-Text ein Objekt zu machen JSON.parse():

Javascript:
var obj = JSON.parse('{"name":"Luke"}');
console.log(obj.name); // Ausgabe: Luke

Natürlich gelten die üblichen Sicherheitsbedenken, man sollte sehr sehr selten irgendwelche Strings oder Dateiinhalte direkt in Objekte parsen, und lokale Dateien eher überhaupt nicht, wenn es vermeidbar ist, und in jedem Fall a.) den Fehler abfangen, falls es kein valides JSON ist und b.) danach sorgfältig prüfen, ob es genau das richtige Objekt ist das man erwartet. Beides hab ich erstmal weg gelassen.

MfG
Danke für deine Antwort, aber das ist nicht das wonach ich suche. Ich weiß bereits, wie man JSON in Objekte und Array parst.
Mein Problem ist, dass ich auf diesen JSON String nicht außerhalb des Fetch-Codeblocks zugreifen kann. Ich will also außerahalb dieses Fetch Blocks auf den importierten (womöglich auch bereits geparsten) JSON String in einer Variable zugreifen.
 
Du hast die statsJson außerhalb der anonymen Funktion schon vorab deklariert, nehme ich mal an?
Das sollte eigentlich gehen.

Poste sonst den Rest vom Code.. also den Teil, in dem du statsJson deklarierst und den Teil danach, in welchem du versuchst, sie aufzurufen.

Vielleicht fragst du sie auch schon ab, bevor das Promise erfüllt ist und vielleicht ist asynchron auch nicht der richtige Weg.
 
Du hast die statsJson außerhalb der anonymen Funktion schon vorab deklariert, nehme ich mal an?
Das sollte eigentlich gehen.

Poste sonst den Rest vom Code.. also den Teil, in dem du statsJson deklarierst und den Teil danach, in welchem du versuchst, sie aufzurufen.

Vielleicht fragst du sie auch schon ab, bevor das Promise erfüllt ist und vielleicht ist asynchron auch nicht der richtige Weg.
Wenn ich statsJson schon vor des Fetch-Blocks deklariert habe, bekomme ich nur ein undefined zurück. Habe ich es vor dem Fetch-Blocks gar nicht deklariert, bekomme ich eine richtige Fehlermeldung, dass statsJson nicht definiert wäre. Das war wohl mein Kommunikationsfehler.

Abgesehen davon, hier der Beispiel-Code:

Javascript:
fetch('stats.json')
    .then((response) => response.text())
    .then((text) => (statsJson = text))
    .then(() => console.log('1: ' + statsJson));

console.log('2: ' + statsJson);

Wahrscheinlich ist der Grund für mein Problem, dass das Promise noch nicht erfüllt ist. Es wird sogar zuerst das hintere Console log ausgeloggt. Ich bin ziemlich neu und habe noch keine Ahnung von asynchronem JS und würde gerne etwas anderes verwenden. Im Internet habe ich aber keinen anderen Lösungsvorschlag gefunden. Kennt ihr eine Alternative? Und wenn nicht, wie kann man Code ausführen, nachdem die asynchrone Funktion beendet ist und das ganze wieder synchron ausführen lassen?
 
Hast du noch Details für mich? Ist das Node? Läuft das über React?

Du schreibst, die JSON-Datei ist lokal. Lokal im Verhältnis zum Server? Dann würde ich sie einfach über das Dateisystem laden, oder über einen Import.

Aber davon abgesehen, sollte fetch eigentlich klappen. Versuch's vielleicht nochmal so (bisschen zu Fuß, statt mit Then-Ketten):

Javascript:
// Als Async markierte Funktion als Hülle
async function loadStats() {
    const promise = await fetch('stats.json');
    return await promise.text();
}

// In Konstante laden, await erzwingt abwarten
const statsJson = await loadStats();

// Ab hier im Rest des Codes verwendbar
console.log(statsJson);

PS: Müsste eigentlich auch mit der eleganteren Form mit .then gehen, aber kann sein, dass du da trotzdem mit await arbeiten musst. Außerdem glaube ich, dass du das Promise auch direkt als JSON-Objekt laden kannst, statt als Text. Sonst musst du das noch parsen, wie @Lowl3v3l geschrieben hatte. Musst mal in der Fetch-API gucken.. war glaube ich blabla.JSON() statt blabla.text() oder so.

Und wenn es nicht lokal ist, solltest du auch Fehlerbehandlung (HTTP-Error Codes) und Timeouts mit reinnehmen.
 
Zuletzt bearbeitet:
Hast du noch Details für mich? Ist das Node? Läuft das über React?

Du schreibst, die JSON-Datei ist lokal. Lokal im Verhältnis zum Server? Dann würde ich sie einfach über das Dateisystem laden, oder über einen Import.

Aber davon abgesehen, sollte fetch eigentlich klappen. Versuch's vielleicht nochmal so (bisschen zu Fuß, statt mit Then-Ketten):

Javascript:
// Als Async markierte Funktion als Hülle
async function loadStats() {
    const promise = await fetch('stats.json');
    return await promise.text();
}

// In Konstante laden, await erzwingt abwarten
const statsJson = await loadStats();

// Ab hier im Rest des Codes verwendbar
console.log(statsJson);

PS: Müsste eigentlich auch mit der eleganteren Form mit .then gehen, aber kann sein, dass du da trotzdem mit await arbeiten musst. Außerdem glaube ich, dass du das Promise auch direkt als JSON-Objekt laden kannst, statt als Text. Sonst musst du das noch parsen, wie @Lowl3v3l geschrieben hatte. Musst mal in der Fetch-API gucken.. war glaube ich blabla.JSON() statt blabla.text() oder so.

Und wenn es nicht lokal ist, solltest du auch Fehlerbehandlung (HTTP-Error Codes) und Timeouts mit reinnehmen.
Danke für deine ausführliche Antwort! Ich benutze weder Node noch irgendwelche Frameworks wie React. Was genau meinst du mit "Lokal im Verhältnis zum Server"? Die JSON Datei und die Website (also auch JS) sind auf demselben Server. Ich habe deinen Vorschlag ausprobiert, jedoch kam bei mir folgende Fehlermeldung:

Uncaught SyntaxError: await is only valid in async functions and async generators

Dazu funtkioniert mein restlicher Code, der über body onload aus dem HTML ausgelöst wird nicht, da er auf der gefetchten Variable basiert und so wie ich das Verstehe schon vor dem Ende der asynchronen Funktion ausgeführt wird und die Variable dadurch noch gar nicht definiert wurde.

Ich hatte noch die Idee, die JSON Datei, abgewandelt in eine JS Datei, ins HTML zu laden (die JSON Datei wird dabei von einem selbstgeschriebenen Python Script erstellt - das Generieren der "JS-Datei" (in der dann nur das JSON als String Variable deklariert wird) hat bereits geklappt). Ich konnte es auch erfolgreich importieren und verwenden, meiner Erfahrung nach hat dies allerdings einen Haken:
JS Dateien werden in Chrome (wahrscheinlich auch in Edge) bei einem normalen Refresh nicht neu geladen, was zur Folge hat, dass das JSON (das sich übrigens täglich verändert) nicht aktuell bleibt.

Am besten wäre es daher, wenn man die JSON Datei einfach über das Dateisystem oder einen Import laden könnte, falls das bei mir funktionieren würde (wie das geht müsste mir dann auch noch erklärt werden :)). Wenn das nicht geht, müsste ich wissen, wie die korrigierte Version deines Code-Vorschlags aussehen würde (also wo der Fehler in der Fehlermeldung behoben wurde) und wie ich es lösen könnte, dass der restliche Code meiner WebApp automatisch beim Laden der Website nach dem Beenden der asynchronen Funktion ausgeführt wird.
 
Hmm. Der Code funzt so direkt in der Entwicklerkonsole von jedem aktuellen Browser. Auf einem Node-Server mit ES6 als Sprachlevel läuft es auch. Und du hast in deinen Beispielen ES6 benutzt, also kann es auch nicht an einem veralteten Dialekt liegen.

Also Client und Server kriegen das beide hin.

Das ist alles in einem onload-Block drin, sagst du?
Dann wird es daran liegen. Hast du ein Beispiel?

Ich denke, du musst onload auch noch async machen oder so (also window.onload = async () ... ). Aber so langsam geht's in eine Richtung, von der ich keine Ahnung hab. Mit mehr Beispielcode könnte ich es sicher durch Rumprobieren zum Laufen kriegen.

Mach mal dein onload async und wenn das nicht geht, weiß vielleicht noch wer anders hier Rat.

Sonst poste ein bisschen mehr Code.. dann kann ich das auch außerhalb meines Schädels ausführen ^^
 
Okay. So sieht das bei mir ungefähr aus:

HTML:
<!DOCTYPE html>
<html>
    <head>
        <title>Coole App</title>
    </head>
    <body onload="statistics()">
        <h1>Lorem ipsum</h1>
        <h3>Dolor sit amet</h3>
        <br />
        <div id="myDiv"></div>
    </body>
</html>
Javascript:
// Als Async markierte Funktion als Hülle
async function loadStats() {
    const promise = await fetch('stats.json');
    return await promise.text();
}

// In Konstante laden, await erzwingt abwarten
const statsJson = await loadStats();

// Ab hier im Rest des Codes verwendbar
stats = JSON.parse(statsJson);

function statistics() {
    console.log(stats);
    document.getElementById('myDiv').innerText = 'Success!';
}
Du hattest vorgeschlagen, die JSON Datei einfach über einen Import oder das Dateisystem zu laden. Würde das bei mir gehen? Und wie würde das dann gehen? Weil das, wenn es funktionieren würde, alles viel einfacher machen würde...
 
Für Importe muss man mit Modulen arbeiten.

Mach es sonst so mit fetch..

Öhm..wenn du schon eine Funktion namens statistics hast, brauchst du ja nicht noch extra loadStats. Versuch mal, die zusammenzufassen.. dann bleibt nur noch sowas in der Art:

Javascript:
async function statistics() {
    let promise = await fetch('stats.json');
    
    let stats = await promise.json();
    console.log(stats);
    document.getElementById('myDiv').innerText = 'Success!';
}
 
Zurück
Oben Unten